summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/ExceptionHandling.rst151
-rw-r--r--docs/LangRef.rst362
-rw-r--r--include/llvm-c/Core.h10
-rw-r--r--include/llvm/Analysis/EHPersonalities.h11
-rw-r--r--include/llvm/Bitcode/LLVMBitCodes.h5
-rw-r--r--include/llvm/CodeGen/WinEHFuncInfo.h6
-rw-r--r--include/llvm/IR/IRBuilder.h30
-rw-r--r--include/llvm/IR/InstVisitor.h8
-rw-r--r--include/llvm/IR/InstrTypes.h73
-rw-r--r--include/llvm/IR/Instruction.def120
-rw-r--r--include/llvm/IR/Instruction.h16
-rw-r--r--include/llvm/IR/Instructions.h508
-rw-r--r--include/llvm/Transforms/Utils/Local.h4
-rw-r--r--lib/Analysis/CaptureTracking.cpp5
-rw-r--r--lib/Analysis/EHPersonalities.cpp65
-rw-r--r--lib/Analysis/InstructionSimplify.cpp6
-rw-r--r--lib/Analysis/LoopInfo.cpp8
-rw-r--r--lib/Analysis/ScalarEvolutionExpander.cpp10
-rw-r--r--lib/Analysis/ValueTracking.cpp3
-rw-r--r--lib/AsmParser/LLLexer.cpp5
-rw-r--r--lib/AsmParser/LLParser.cpp284
-rw-r--r--lib/AsmParser/LLParser.h29
-rw-r--r--lib/AsmParser/LLToken.h6
-rw-r--r--lib/Bitcode/Reader/BitcodeReader.cpp234
-rw-r--r--lib/Bitcode/Writer/BitcodeWriter.cpp62
-rw-r--r--lib/CodeGen/AsmPrinter/WinException.cpp113
-rw-r--r--lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp4
-rw-r--r--lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp63
-rw-r--r--lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h3
-rw-r--r--lib/CodeGen/TargetLoweringBase.cpp9
-rw-r--r--lib/CodeGen/WinEHPrepare.cpp1685
-rw-r--r--lib/IR/AsmWriter.cpp66
-rw-r--r--lib/IR/Dominators.cpp28
-rw-r--r--lib/IR/Instruction.cpp9
-rw-r--r--lib/IR/Instructions.cpp347
-rw-r--r--lib/IR/Verifier.cpp155
-rw-r--r--lib/Target/X86/X86WinEHState.cpp24
-rw-r--r--lib/Transforms/Instrumentation/MemorySanitizer.cpp14
-rw-r--r--lib/Transforms/Scalar/Reassociate.cpp2
-rw-r--r--lib/Transforms/Scalar/SCCP.cpp6
-rw-r--r--lib/Transforms/Scalar/Sink.cpp8
-rw-r--r--lib/Transforms/Utils/CodeExtractor.cpp6
-rw-r--r--lib/Transforms/Utils/InlineFunction.cpp142
-rw-r--r--lib/Transforms/Utils/LCSSA.cpp8
-rw-r--r--lib/Transforms/Utils/Local.cpp18
-rw-r--r--lib/Transforms/Utils/SimplifyCFG.cpp23
-rw-r--r--test/Assembler/invalid-OperatorConstraint.ll89
-rw-r--r--test/Bitcode/compatibility.ll106
-rw-r--r--test/CodeGen/WinEH/wineh-cloning.ll398
-rw-r--r--test/CodeGen/WinEH/wineh-demotion.ll121
-rw-r--r--test/CodeGen/WinEH/wineh-intrinsics.ll14
-rw-r--r--test/CodeGen/WinEH/wineh-multi-parent-cloning.ll1548
-rw-r--r--test/CodeGen/WinEH/wineh-no-demotion.ll78
-rw-r--r--test/CodeGen/WinEH/wineh-statenumbering-cleanups.ll68
-rw-r--r--test/CodeGen/WinEH/wineh-statenumbering.ll31
-rw-r--r--test/CodeGen/X86/branchfolding-catchpads.ll45
-rw-r--r--test/CodeGen/X86/catchpad-realign-savexmm.ll14
-rw-r--r--test/CodeGen/X86/catchpad-regmask.ll18
-rw-r--r--test/CodeGen/X86/catchpad-weight.ll27
-rw-r--r--test/CodeGen/X86/catchret-empty-fallthrough.ll9
-rw-r--r--test/CodeGen/X86/catchret-fallthrough.ll9
-rw-r--r--test/CodeGen/X86/cleanuppad-inalloca.ll4
-rw-r--r--test/CodeGen/X86/cleanuppad-large-codemodel.ll4
-rw-r--r--test/CodeGen/X86/cleanuppad-realign.ll4
-rw-r--r--test/CodeGen/X86/funclet-layout.ll69
-rw-r--r--test/CodeGen/X86/late-address-taken.ll10
-rw-r--r--test/CodeGen/X86/seh-catch-all-win32.ll11
-rw-r--r--test/CodeGen/X86/seh-catch-all.ll11
-rw-r--r--test/CodeGen/X86/seh-catchpad.ll61
-rw-r--r--test/CodeGen/X86/seh-except-finally.ll25
-rw-r--r--test/CodeGen/X86/seh-exception-code.ll11
-rw-r--r--test/CodeGen/X86/seh-finally.ll12
-rw-r--r--test/CodeGen/X86/seh-safe-div-win32.ll26
-rw-r--r--test/CodeGen/X86/seh-safe-div.ll26
-rw-r--r--test/CodeGen/X86/seh-stack-realign.ll11
-rw-r--r--test/CodeGen/X86/tail-dup-catchret.ll9
-rw-r--r--test/CodeGen/X86/tail-merge-wineh.ll29
-rw-r--r--test/CodeGen/X86/win-catchpad-csrs.ll62
-rw-r--r--test/CodeGen/X86/win-catchpad-nested-cxx.ll105
-rw-r--r--test/CodeGen/X86/win-catchpad-nested.ll35
-rw-r--r--test/CodeGen/X86/win-catchpad-varargs.ll9
-rw-r--r--test/CodeGen/X86/win-catchpad.ll105
-rw-r--r--test/CodeGen/X86/win-cleanuppad.ll12
-rw-r--r--test/CodeGen/X86/win-funclet-cfi.ll15
-rw-r--r--test/CodeGen/X86/win-mixed-ehpersonality.ll10
-rw-r--r--test/CodeGen/X86/win32-eh-states.ll183
-rw-r--r--test/CodeGen/X86/win32-eh.ll30
-rw-r--r--test/CodeGen/X86/win32-seh-catchpad-realign.ll11
-rw-r--r--test/CodeGen/X86/win32-seh-catchpad.ll76
-rw-r--r--test/CodeGen/X86/win32-seh-nested-finally.ll (renamed from test/CodeGen/X86/win32-seh-cleanupendpad.ll)21
-rw-r--r--test/CodeGen/X86/wineh-coreclr.ll (renamed from test/CodeGen/WinEH/wineh-coreclr.ll)146
-rw-r--r--test/CodeGen/X86/wineh-exceptionpointer.ll (renamed from test/CodeGen/WinEH/wineh-exceptionpointer.ll)14
-rw-r--r--test/Feature/exception.ll129
-rw-r--r--test/Transforms/CodeGenPrepare/catchpad-phi-cast.ll52
-rw-r--r--test/Transforms/GVN/funclet.ll9
-rw-r--r--test/Transforms/GVN/pre-load.ll26
-rw-r--r--test/Transforms/Inline/PR25155.ll21
-rw-r--r--test/Transforms/InstCombine/token.ll24
-rw-r--r--test/Transforms/LoopStrengthReduce/funclet.ll80
-rw-r--r--test/Transforms/LoopStrengthReduce/pr25541.ll13
-rw-r--r--test/Transforms/LoopUnswitch/cleanuppad.ll44
-rw-r--r--test/Transforms/SimplifyCFG/empty-cleanuppad.ll155
-rw-r--r--test/Transforms/SimplifyCFG/wineh-unreachable.ll48
-rw-r--r--test/Transforms/Sink/catchswitch.ll37
-rw-r--r--test/Verifier/invalid-eh.ll38
-rw-r--r--tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp2
106 files changed, 3078 insertions, 6086 deletions
diff --git a/docs/ExceptionHandling.rst b/docs/ExceptionHandling.rst
index 5b495d9863c..12899ed8380 100644
--- a/docs/ExceptionHandling.rst
+++ b/docs/ExceptionHandling.rst
@@ -522,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
@@ -618,10 +614,11 @@ 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``, ``cleanuppad``, and ``terminatepad``.
+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
+invoke that unwinds to a ``catchswitch`` 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
@@ -634,26 +631,20 @@ 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
-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.
+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`` and ``terminatepad``
+instructions are terminators, and have a 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:
@@ -694,33 +685,95 @@ 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, %invoke.cont.3
- %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
- %cleanup = cleanuppad []
- call void @"\01??_DCleanup@@QEAA@XZ"(%struct.Cleanup* nonnull %obj) nounwind
- cleanupret %cleanup unwind label %lpad.catch
+ 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.catch: ; preds = %entry, %lpad.cleanup
- %catch = catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i32* %e]
- to label %catch.body unwind label %catchend
+ 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 %catchend
+ to label %invoke.cont.3 unwind label %lpad.terminate
invoke.cont.3: ; preds = %catch.body
- %9 = load i32, i32* %e, align 4
- catchret %catch to label %return
+ %3 = load i32, i32* %e, align 4
+ catchret from %catch to label %return
+
+ lpad.terminate: ; preds = %catch.body, %lpad.catch
+ terminatepad within none [void ()* @"\01?terminate@@YAXXZ"] unwind to caller
+ }
+
+Funclet parent tokens
+-----------------------
- catchend: ; preds = %lpad.catch, %catch.body
- catchendpad 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.
- lpad.terminate: ; preds = %catchend
- terminatepad [void ()* @"\01?terminate@@YAXXZ"]
- unwind to caller
+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. The ``terminatepad`` instruction cannot contain lexically nested
+funclets inside the termination action, so it does not produce a token.
+
+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.
diff --git a/docs/LangRef.rst b/docs/LangRef.rst
index 58198f7af7d..09efa75515c 100644
--- a/docs/LangRef.rst
+++ b/docs/LangRef.rst
@@ -5001,10 +5001,8 @@ control flow, not values (the one exception being the
The terminator instructions are: ':ref:`ret <i_ret>`',
':ref:`br <i_br>`', ':ref:`switch <i_switch>`',
':ref:`indirectbr <i_indirectbr>`', ':ref:`invoke <i_invoke>`',
-':ref:`resume <i_resume>`', ':ref:`catchpad <i_catchpad>`',
-':ref:`catchendpad <i_catchendpad>`',
+':ref:`resume <i_resume>`', ':ref:`catchswitch <i_catchswitch>`',
':ref:`catchret <i_catchret>`',
-':ref:`cleanupendpad <i_cleanupendpad>`',
':ref:`cleanupret <i_cleanupret>`',
':ref:`terminatepad <i_terminatepad>`',
and ':ref:`unreachable <i_unreachable>`'.
@@ -5362,9 +5360,9 @@ Example:
resume { i8*, i32 } %exn
-.. _i_catchpad:
+.. _i_catchswitch:
-'``catchpad``' Instruction
+'``catchswitch``' Instruction
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Syntax:
@@ -5372,155 +5370,125 @@ Syntax:
::
- <resultval> = catchpad [<args>*]
- to label <normal label> unwind label <exception label>
+ <resultval> = catchswitch within <parent> [ label <handler1>, label <handler2>, ... ] unwind to caller
+ <resultval> = catchswitch within <parent> [ label <handler1>, label <handler2>, ... ] unwind label <default>
Overview:
"""""""""
-The '``catchpad``' instruction is used by `LLVM's exception handling
-system <ExceptionHandling.html#overview>`_ to specify that a basic block
-is a catch block --- one where a personality routine attempts to transfer
-control to catch an exception.
-The ``args`` correspond to whatever information the personality
-routine requires to know if this is an appropriate place to catch the
-exception. Control is transfered 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. The ``resultval`` has the type
-:ref:`token <t_token>` and is used to match the ``catchpad`` to
-corresponding :ref:`catchrets <i_catchret>`.
+The '``catchswitch``' instruction is used by `LLVM's exception handling system
+<ExceptionHandling.html#overview>`_ to describe the set of possible catch handlers
+that may be executed by the :ref:`EH personality routine <personalityfn>`.
Arguments:
""""""""""
-The instruction takes a list of arbitrary values which are interpreted
-by the :ref:`personality function <personalityfn>`.
+The ``parent`` argument is the token of the funclet that contains the
+``catchswitch`` instruction. If the ``catchswitch`` is not inside a funclet,
+this operand may be the token ``none``.
-The ``catchpad`` must be provided a ``normal`` label to transfer control
-to if the ``catchpad`` matches the exception and an ``exception``
-label to transfer control to if it doesn't.
+The ``default`` argument is the label of another basic block beginning with a
+"pad" instruction, one of ``cleanuppad``, ``terminatepad``, or
+``catchswitch``.
+
+The ``handlers`` are a list of successor blocks that each begin with a
+:ref:`catchpad <i_catchpad>` instruction.
Semantics:
""""""""""
-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.
+Executing this instruction transfers control to one of the successors in
+``handlers``, if appropriate, or continues to unwind via the unwind label if
+present.
-The ``catchpad`` instruction has several restrictions:
-
-- A catch block is a basic block which is the unwind destination of
- an exceptional instruction.
-- A catch block must have a '``catchpad``' instruction as its
- first non-PHI instruction.
-- A catch block's ``exception`` edge must refer to a catch block or a
- catch-end block.
-- There can be only one '``catchpad``' instruction within the
- 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
- ``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``.
+The ``catchswitch`` is both a terminator and a "pad" instruction, meaning that
+it must be both the first non-phi instruction and last instruction in the basic
+block. Therefore, it must be the only non-phi instruction in the block.
Example:
""""""""
.. code-block:: llvm
- ;; A catch block which can catch an integer.
- %tok = catchpad [i8** @_ZTIi]
- to label %int.handler unwind label %terminate
+ dispatch1:
+ %cs1 = catchswitch within none [label %handler0, label %handler1] unwind to caller
+ dispatch2:
+ %cs2 = catchswitch within %parenthandler [label %handler0] unwind label %cleanup
-.. _i_catchendpad:
+.. _i_catchpad:
-'``catchendpad``' Instruction
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+'``catchpad``' Instruction
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Syntax:
"""""""
::
- catchendpad unwind label <nextaction>
- catchendpad unwind to caller
+ <resultval> = catchpad within <catchswitch> [<args>*]
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
-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
-in-flight exception.
-
-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.
+The '``catchpad``' instruction is used by `LLVM's exception handling
+system <ExceptionHandling.html#overview>`_ to specify that a basic block
+begins a catch handler --- one where a personality routine attempts to transfer
+control to catch an exception.
Arguments:
""""""""""
-The instruction optionally takes a label, ``nextaction``, indicating
-where control should transfer to if none of the preceding
-``catchpad`` instructions are suitable for the in-flight exception.
+The ``catchswitch`` operand must always be a token produced by a
+:ref:`catchswitch <i_catchswitch>` instruction in a predecessor block. This
+ensures that each ``catchpad`` has exactly one predecessor block, and it always
+terminates in a ``catchswitch``.
+
+The ``args`` correspond to whatever information the personality routine
+requires to know if this is an appropriate handler for the exception. Control
+will transfer to the ``catchpad`` if this is the first appropriate handler for
+the exception.
+
+The ``resultval`` has the type :ref:`token <t_token>` and is used to match the
+``catchpad`` to corresponding :ref:`catchrets <i_catchret>` and other nested EH
+pads.
Semantics:
""""""""""
-When the call stack is being unwound due to an exception being thrown
-and none of the constituent ``catchpad`` instructions match, then
-control is transfered to ``nextaction`` if it is present. If it is not
-present, control is transfered to the caller.
+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, control will
+not reach the ``catchpad`` instruction. The representation of ``args`` is
+entirely target and personality function-specific.
-The ``catchendpad`` instruction has several restrictions:
+Like the :ref:`landingpad <i_landingpad>` instruction, the ``catchpad``
+instruction must be the first non-phi of its parent basic block.
-- A catch-end block is a basic block which is the unwind destination of
- an exceptional instruction.
-- 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-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``.
-- 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.
+The meaning of the tokens produced and consumed by ``catchpad`` and other "pad"
+instructions is described in the
+`Windows exception handling documentation <ExceptionHandling.html#wineh>`.
+
+Executing a ``catchpad`` instruction constitutes "entering" that pad.
+The pad may then be "exited" in one of three ways:
+1) explicitly via a ``catchret`` that consumes it. Executing such a ``catchret``
+ is undefined behavior if any descendant pads have been entered but not yet
+ exited.
+2) implicitly via a call (which unwinds all the way to the current function's caller),
+ or via a ``catchswitch``, ``cleanupret``, or ``terminatepad`` that unwinds to caller.
+3) implicitly via an unwind edge whose destination EH pad isn't a descendant of
+ the ``catchpad``. When the ``catchpad`` is exited in this manner, it is
+ undefined behavior if the destination EH pad has a parent which is not an
+ ancestor of the ``catchpad`` being exited.
Example:
""""""""
.. code-block:: llvm
- catchendpad unwind label %terminate
- catchendpad unwind to caller
+ dispatch:
+ %cs = catchswitch within none [label %handler0] unwind to caller
+ ;; A catch block which can catch an integer.
+ handler0:
+ %tok = catchpad within %cs [i8** @_ZTIi]
.. _i_catchret:
@@ -5532,7 +5500,7 @@ Syntax:
::
- catchret <value> to label <normal>
+ catchret from <token> to label <normal>
Overview:
"""""""""
@@ -5552,105 +5520,24 @@ transfer to next.
Semantics:
""""""""""
-The '``catchret``' instruction ends the existing (in-flight) exception
-whose unwinding was interrupted with a
-:ref:`catchpad <i_catchpad>` instruction.
-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, 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:
-""""""""
-
-.. code-block:: llvm
-
- 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 '``catchret``' instruction ends an existing (in-flight) exception whose
+unwinding was interrupted with a :ref:`catchpad <i_catchpad>` instruction. The
+:ref:`personality function <personalityfn>` gets a chance to execute arbitrary
+code to, for example, destroy the active exception. Control then transfers to
+``normal``.
-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.
+The ``token`` argument must be a token produced by a dominating ``catchpad``
+instruction. The ``catchret`` destroys the physical frame established by
+``catchpad``, so executing multiple returns on the same token without
+re-executing the ``catchpad`` will result in undefined behavior.
+See :ref:`catchpad <i_catchpad>` for more details.
Example:
""""""""
.. code-block:: llvm
- cleanupendpad %cleanup unwind label %terminate
- cleanupendpad %cleanup unwind to caller
+ catchret from %catch label %continue
.. _i_cleanupret:
@@ -5662,8 +5549,8 @@ Syntax:
::
- cleanupret <value> unwind label <continue>
- cleanupret <value> unwind to caller
+ cleanupret from <value> unwind label <continue>
+ cleanupret from <value> unwind to caller
Overview:
"""""""""
@@ -5687,25 +5574,20 @@ The '``cleanupret``' instruction indicates to the
: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, 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.
+The unwind destination ``continue``, if present, must be an EH pad
+whose parent is either ``none`` or an ancestor of the ``cleanuppad``
+being returned from. This constitutes an exceptional exit from all
+ancestors of the completed ``cleanuppad``, up to but not including
+the parent of ``continue``.
+See :ref:`cleanuppad <i_cleanuppad>` for more details.
Example:
""""""""
.. code-block:: llvm
- cleanupret %cleanup unwind to caller
- cleanupret %cleanup unwind label %continue
+ cleanupret from %cleanup unwind to caller
+ cleanupret from %cleanup unwind label %continue
.. _i_terminatepad:
@@ -5717,8 +5599,8 @@ Syntax:
::
- terminatepad [<args>*] unwind label <exception label>
- terminatepad [<args>*] unwind to caller
+ terminatepad within <token> [<args>*] unwind label <exception label>
+ terminatepad within <token> [<args>*] unwind to caller
Overview:
"""""""""
@@ -5752,16 +5634,8 @@ the program is terminated via personality-specific means. Typically,
the first argument to ``terminatepad`` specifies what function the
personality should defer to in order to terminate the program.
-The ``terminatepad`` instruction has several restrictions:
-
-- A terminate block is a basic block which is the unwind destination of
- an exceptional instruction.
-- A terminate block must have a '``terminatepad``' instruction as its
- first non-PHI instruction.
-- There can be only one '``terminatepad``' instruction within the
- terminate block.
-- A basic block that is not a terminate block may not include a
- '``terminatepad``' instruction.
+The ``terminatepad`` instruction is both a terminator and a "pad" instruction,
+meaning that is always the only non-phi instruction in the basic block.
Example:
""""""""
@@ -5769,7 +5643,7 @@ Example:
.. code-block:: llvm
;; A terminate block which only permits integers.
- terminatepad [i8** @_ZTIi] unwind label %continue
+ terminatepad within none [i8** @_ZTIi] unwind label %continue
.. _i_unreachable:
@@ -8762,7 +8636,7 @@ Syntax:
::
- <resultval> = cleanuppad [<args>*]
+ <resultval> = cleanuppad within <parent> [<args>*]
Overview:
"""""""""
@@ -8775,8 +8649,10 @@ 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
-match the ``cleanuppad`` to corresponding :ref:`cleanuprets <i_cleanupret>`
-and :ref:`cleanupendpads <i_cleanupendpad>`.
+match the ``cleanuppad`` to corresponding :ref:`cleanuprets <i_cleanupret>`.
+The ``parent`` argument is the token of the funclet that contains the
+``cleanuppad`` instruction. If the ``cleanuppad`` is not inside a funclet,
+this operand may be the token ``none``.
Arguments:
""""""""""
@@ -8803,21 +8679,29 @@ 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 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
- ``ret`` without first executing a ``cleanupret`` or ``cleanupendpad`` that
- consumes the ``cleanuppad``.
-- It is undefined behavior for control to transfer from a ``cleanuppad`` to
- itself without first executing a ``cleanupret`` or ``cleanupendpad`` that
- consumes the ``cleanuppad``.
+
+Executing a ``cleanuppad`` instruction constitutes "entering" that pad.
+The pad may then be "exited" in one of three ways:
+1) explicitly via a ``cleanupret`` that consumes it. Executing such a ``cleanupret``
+ is undefined behavior if any descendant pads have been entered but not yet
+ exited.
+2) implicitly via a call (which unwinds all the way to the current function's caller),
+ or via a ``catchswitch``, ``cleanupret``, or ``terminatepad`` that unwinds to caller.
+3) implicitly via an unwind edge whose destination EH pad isn't a descendant of
+ the ``cleanuppad``. When the ``cleanuppad`` is exited in this manner, it is
+ undefined behavior if the destination EH pad has a parent which is not an
+ ancestor of the ``cleanuppad`` being exited.
+
+It is undefined behavior for the ``cleanuppad`` to exit via an unwind edge which
+does not transitively unwind to the same destination as a constituent
+``cleanupret``.
Example:
""""""""
.. code-block:: llvm
- %tok = cleanuppad []
+ %tok = cleanuppad within %cs []
.. _intrinsics:
diff --git a/include/llvm-c/Core.h b/include/llvm-c/Core.h
index 8157e9cf869..e84dd39092f 100644
--- a/include/llvm-c/Core.h
+++ b/include/llvm-c/Core.h
@@ -254,8 +254,7 @@ typedef enum {
LLVMCatchPad = 63,
LLVMTerminatePad = 64,
LLVMCleanupPad = 65,
- LLVMCatchEndPad = 66,
- LLVMCleanupEndPad = 67
+ LLVMCatchSwitch = 66
} LLVMOpcode;
typedef enum {
@@ -1211,7 +1210,6 @@ LLVMTypeRef LLVMX86MMXType(void);
macro(InsertElementInst) \
macro(InsertValueInst) \
macro(LandingPadInst) \
- macro(CleanupPadInst) \
macro(PHINode) \
macro(SelectInst) \
macro(ShuffleVectorInst) \
@@ -1226,10 +1224,10 @@ LLVMTypeRef LLVMX86MMXType(void);
macro(ResumeInst) \
macro(CleanupReturnInst) \
macro(CatchReturnInst) \
- macro(CatchPadInst) \
macro(TerminatePadInst) \
- macro(CatchEndPadInst) \
- macro(CleanupEndPadInst) \
+ macro(FuncletPadInst) \
+ macro(CatchPadInst) \
+ macro(CleanupPadInst) \
macro(UnaryInstruction) \
macro(AllocaInst) \
macro(CastInst) \
diff --git a/include/llvm/Analysis/EHPersonalities.h b/include/llvm/Analysis/EHPersonalities.h
index 4a56728fbb4..59e9672b88e 100644
--- a/include/llvm/Analysis/EHPersonalities.h
+++ b/include/llvm/Analysis/EHPersonalities.h
@@ -10,9 +10,12 @@
#ifndef LLVM_ANALYSIS_EHPERSONALITIES_H
#define LLVM_ANALYSIS_EHPERSONALITIES_H
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Support/ErrorHandling.h"
namespace llvm {
+class BasicBlock;
class Function;
class Value;
@@ -78,6 +81,14 @@ inline bool isNoOpWithoutInvoke(EHPersonality Pers) {
bool canSimplifyInvokeNoUnwind(const Function *F);
+typedef TinyPtrVector<BasicBlock *> ColorVector;
+
+/// \brief If an EH funclet personality is in use (see isFuncletEHPersonality),
+/// this will recompute which blocks are in which funclet. It is possible that
+/// some blocks are in multiple funclets. Consider this analysis to be
+/// expensive.
+DenseMap<BasicBlock *, ColorVector> colorEHFunclets(Function &F);
+
} // end namespace llvm
#endif
diff --git a/include/llvm/Bitcode/LLVMBitCodes.h b/include/llvm/Bitcode/LLVMBitCodes.h
index 55fe05938e6..9bd3c9ea061 100644
--- a/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/include/llvm/Bitcode/LLVMBitCodes.h
@@ -423,9 +423,8 @@ enum { BITCODE_CURRENT_EPOCH = 0 };
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#]
- FUNC_CODE_INST_CLEANUPENDPAD = 54, // CLEANUPENDPAD: [val] or [val,bb#]
-
+ FUNC_CODE_INST_CATCHSWITCH = 53, // CATCHSWITCH: [num,args...] or [num,args...,bb]
+ // 54 is unused.
FUNC_CODE_OPERAND_BUNDLE = 55, // OPERAND_BUNDLE: [tag#, value...]
};
diff --git a/include/llvm/CodeGen/WinEHFuncInfo.h b/include/llvm/CodeGen/WinEHFuncInfo.h
index 5e8bb56eb61..599f8595043 100644
--- a/include/llvm/CodeGen/WinEHFuncInfo.h
+++ b/include/llvm/CodeGen/WinEHFuncInfo.h
@@ -89,9 +89,11 @@ struct ClrEHUnwindMapEntry {
struct WinEHFuncInfo {
DenseMap<const Instruction *, int> EHPadStateMap;
+ DenseMap<const FuncletPadInst *, int> FuncletBaseStateMap;
+ DenseMap<const InvokeInst *, int> InvokeStateMap;
DenseMap<const CatchReturnInst *, const BasicBlock *>
CatchRetSuccessorColorMap;
- DenseMap<MCSymbol *, std::pair<int, MCSymbol *>> InvokeToStateMap;
+ DenseMap<MCSymbol *, std::pair<int, MCSymbol *>> LabelToStateMap;
SmallVector<CxxUnwindMapEntry, 4> CxxUnwindMap;
SmallVector<WinEHTryBlockMapEntry, 4> TryBlockMap;
SmallVector<SEHUnwindMapEntry, 4> SEHUnwindMap;
@@ -101,7 +103,7 @@ struct WinEHFuncInfo {
int getLastStateNumber() const { return CxxUnwindMap.size() - 1; }
- void addIPToStateRange(const BasicBlock *PadBB, MCSymbol *InvokeBegin,
+ void addIPToStateRange(const InvokeInst *II, MCSymbol *InvokeBegin,
MCSymbol *InvokeEnd);
int EHRegNodeFrameIndex = INT_MAX;
diff --git a/include/llvm/IR/IRBuilder.h b/include/llvm/IR/IRBuilder.h
index 5f0aa3374ee..2425c31c166 100644
--- a/include/llvm/IR/IRBuilder.h
+++ b/include/llvm/IR/IRBuilder.h
@@ -708,29 +708,29 @@ public:
return Insert(CleanupReturnInst::Create(CleanupPad, UnwindBB));
}
- CleanupEndPadInst *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);
+ CatchSwitchInst *CreateCatchSwitch(Value *ParentPad, BasicBlock *UnwindBB,
+ unsigned NumHandlers,
+ const Twine &Name = "") {
+ return Insert(CatchSwitchInst::Create(ParentPad, UnwindBB, NumHandlers),
+ Name);
}
- CatchEndPadInst *CreateCatchEndPad(BasicBlock *UnwindBB = nullptr) {
- return Insert(CatchEndPadInst::Create(Context, UnwindBB));
+ CatchPadInst *CreateCatchPad(Value *ParentPad, ArrayRef<Value *> Args,
+ const Twine &Name = "") {
+ return Insert(CatchPadInst::Create(ParentPad, Args), Name);
}
- TerminatePadInst *CreateTerminatePad(BasicBlock *UnwindBB = nullptr,
- ArrayRef<Value *> Args = {},
+ TerminatePadInst *CreateTerminatePad(Value *ParentPad,
+ BasicBlock *UnwindBB = nullptr,
+ ArrayRef<Value *> Args = None,
const Twine &Name = "") {
- return Insert(TerminatePadInst::Create(Context, UnwindBB, Args), Name);
+ return Insert(TerminatePadInst::Create(ParentPad, UnwindBB, Args), Name);
}
- CleanupPadInst *CreateCleanupPad(ArrayRef<Value *> Args,
+ CleanupPadInst *CreateCleanupPad(Value *ParentPad,
+ ArrayRef<Value *> Args = None,
const Twine &Name = "") {
- return Insert(CleanupPadInst::Create(Context, Args), Name);
+ return Insert(CleanupPadInst::Create(ParentPad, Args), Name);
}
CatchReturnInst *CreateCatchRet(CatchPadInst *CatchPad, BasicBlock *BB) {
diff --git a/include/llvm/IR/InstVisitor.h b/include/llvm/IR/InstVisitor.h
index 0fe88980b41..d848f91b27b 100644
--- a/include/llvm/IR/InstVisitor.h
+++ b/include/llvm/IR/InstVisitor.h
@@ -170,10 +170,8 @@ public:
RetTy visitResumeInst(ResumeInst &I) { DELEGATE(TerminatorInst);}
RetTy visitUnreachableInst(UnreachableInst &I) { DELEGATE(TerminatorInst);}
RetTy visitCleanupReturnInst(CleanupReturnInst &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 visitCatchSwitchInst(CatchSwitchInst &I) { DELEGATE(TerminatorInst);}
RetTy visitTerminatePadInst(TerminatePadInst &I) { DELEGATE(TerminatorInst);}
RetTy visitICmpInst(ICmpInst &I) { DELEGATE(CmpInst);}
RetTy visitFCmpInst(FCmpInst &I) { DELEGATE(CmpInst);}
@@ -206,7 +204,9 @@ public:
RetTy visitExtractValueInst(ExtractValueInst &I){ DELEGATE(UnaryInstruction);}
RetTy visitInsertValueInst(InsertValueInst &I) { DELEGATE(Instruction); }
RetTy visitLandingPadInst(LandingPadInst &I) { DELEGATE(Instruction); }
- RetTy visitCleanupPadInst(CleanupPadInst &I) { DELEGATE(Instruction); }
+ RetTy visitFuncletPadInst(FuncletPadInst &I) { DELEGATE(Instruction); }
+ RetTy visitCleanupPadInst(CleanupPadInst &I) { DELEGATE(FuncletPadInst); }
+ RetTy visitCatchPadInst(CatchPadInst &I) { DELEGATE(FuncletPadInst); }
// Handle the special instrinsic instruction classes.
RetTy visitDbgDeclareInst(DbgDeclareInst &I) { DELEGATE(DbgInfoIntrinsic);}
diff --git a/include/llvm/IR/InstrTypes.h b/include/llvm/IR/InstrTypes.h
index 2a092726665..76430857994 100644
--- a/include/llvm/IR/InstrTypes.h
+++ b/include/llvm/IR/InstrTypes.h
@@ -82,10 +82,8 @@ public:
// \brief Returns true if this terminator relates to exception handling.
bool isExceptional() const {
switch (getOpcode()) {
- case Instruction::CatchPad:
- case Instruction::CatchEndPad:
+ case Instruction::CatchSwitch:
case Instruction::CatchRet:
- case Instruction::CleanupEndPad:
case Instruction::CleanupRet:
case Instruction::Invoke:
case Instruction::Resume:
@@ -1112,6 +1110,75 @@ struct OperandTraits<CmpInst> : public FixedNumOperandTraits<CmpInst, 2> {
DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CmpInst, Value)
+//===----------------------------------------------------------------------===//
+// FuncletPadInst Class
+//===----------------------------------------------------------------------===//
+class FuncletPadInst : public Instruction {
+private:
+ void init(Value *ParentPad, ArrayRef<Value *> Args, const Twine &NameStr);
+
+ FuncletPadInst(const FuncletPadInst &CPI);
+
+ explicit FuncletPadInst(Instruction::FuncletPadOps Op, Value *ParentPad,
+ ArrayRef<Value *> Args, unsigned Values,
+ const Twine &NameStr, Instruction *InsertBefore);
+ explicit FuncletPadInst(Instruction::FuncletPadOps Op, Value *ParentPad,
+ ArrayRef<Value *> Args, unsigned Values,
+ const Twine &NameStr, BasicBlock *InsertAtEnd);
+
+protected:
+ // Note: Instruction needs to be a friend here to call cloneImpl.
+ friend class Instruction;
+ friend class CatchPadInst;
+ friend class CleanupPadInst;
+ FuncletPadInst *cloneImpl() const;
+
+public:
+ /// Provide fast operand accessors
+ DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
+
+ /// getNumArgOperands - Return the number of funcletpad arguments.
+ ///
+ unsigned getNumArgOperands() const { return getNumOperands() - 1; }
+
+ /// Convenience accessors
+
+ /// \brief Return the outer EH-pad this funclet is nested within.
+ ///
+ /// Note: This returns the associated CatchSwitchInst if this FuncletPadInst
+ /// is a CatchPadInst.
+ Value *getParentPad() const { return Op<-1>(); }
+ void setParentPad(Value *ParentPad) {
+ assert(ParentPad);
+ Op<-1>() = ParentPad;
+ }
+
+ /// getArgOperand/setArgOperand - Return/set the i-th funcletpad argument.
+ ///
+ Value *getArgOperand(unsigned i) const { return getOperand(i); }
+ void setArgOperand(unsigned i, Value *v) { setOperand(i, v); }
+
+ /// arg_operands - iteration adapter for range-for loops.
+ op_range arg_operands() { return op_range(op_begin(), op_end() - 1); }
+
+ /// arg_operands - iteration adapter for range-for loops.
+ const_op_range arg_operands() const {
+ return const_op_range(op_begin(), op_end() - 1);
+ }
+
+ // Methods for support type inquiry through isa, cast, and dyn_cast:
+ static inline bool classof(const Instruction *I) { return I->isFuncletPad(); }
+ static inline bool classof(const Value *V) {
+ return isa<Instruction>(V) && classof(cast<Instruction>(V));
+ }
+};
+
+template <>
+struct OperandTraits<FuncletPadInst>
+ : public VariadicOperandTraits<FuncletPadInst, /*MINARITY=*/1> {};
+
+DEFINE_TRANSPARENT_OPERAND_ACCESSORS(FuncletPadInst, Value)
+
/// \brief A lightweight accessor for an operand bundle meant to be passed
/// around by value.
struct OperandBundleUse {
diff --git a/include/llvm/IR/Instruction.def b/include/llvm/IR/Instruction.def
index 54e4083d15f..1f30e305196 100644
--- a/include/llvm/IR/Instruction.def
+++ b/include/llvm/IR/Instruction.def
@@ -74,6 +74,20 @@
#define LAST_CAST_INST(num)
#endif
+#ifndef FIRST_FUNCLETPAD_INST
+#define FIRST_FUNCLETPAD_INST(num)
+#endif
+#ifndef HANDLE_FUNCLETPAD_INST
+#ifndef HANDLE_INST
+#define HANDLE_FUNCLETPAD_INST(num, opcode, Class)
+#else
+#define HANDLE_FUNCLETPAD_INST(num, opcode, Class) HANDLE_INST(num, opcode, Class)
+#endif
+#endif
+#ifndef LAST_FUNCLETPAD_INST
+#define LAST_FUNCLETPAD_INST(num)
+#endif
+
#ifndef FIRST_OTHER_INST
#define FIRST_OTHER_INST(num)
#endif
@@ -102,65 +116,68 @@ 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 (10, CatchPad , CatchPadInst)
+HANDLE_TERM_INST (10, CatchSwitch , CatchSwitchInst)
HANDLE_TERM_INST (11, TerminatePad , TerminatePadInst)
-HANDLE_TERM_INST (12, CatchEndPad , CatchEndPadInst)
-HANDLE_TERM_INST (13, CleanupEndPad , CleanupEndPadInst)
- LAST_TERM_INST (13)
+ LAST_TERM_INST (11)
// Standard binary operators...
- 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)
+ FIRST_BINARY_INST(12)
+HANDLE_BINARY_INST(12, Add , BinaryOperator)
+HANDLE_BINARY_INST(13, FAdd , BinaryOperator)
+HANDLE_BINARY_INST(14, Sub , BinaryOperator)
+HANDLE_BINARY_INST(15, FSub , BinaryOperator)
+HANDLE_BINARY_INST(16, Mul , BinaryOperator)
+HANDLE_BINARY_INST(17, FMul , BinaryOperator)
+HANDLE_BINARY_INST(18, UDiv , BinaryOperator)
+HANDLE_BINARY_INST(19, SDiv , BinaryOperator)
+HANDLE_BINARY_INST(20, FDiv , BinaryOperator)
+HANDLE_BINARY_INST(21, URem , BinaryOperator)
+HANDLE_BINARY_INST(22, SRem , BinaryOperator)
+HANDLE_BINARY_INST(23, FRem , BinaryOperator)
// Logical operators (integer operands)
-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)
+HANDLE_BINARY_INST(24, Shl , BinaryOperator) // Shift left (logical)
+HANDLE_BINARY_INST(25, LShr , BinaryOperator) // Shift right (logical)
+HANDLE_BINARY_INST(26, AShr , BinaryOperator) // Shift right (arithmetic)
+HANDLE_BINARY_INST(27, And , BinaryOperator)
+HANDLE_BINARY_INST(28, Or , BinaryOperator)
+HANDLE_BINARY_INST(29, Xor , BinaryOperator)
+ LAST_BINARY_INST(29)
// Memory operators...
- 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)
+ FIRST_MEMORY_INST(30)
+HANDLE_MEMORY_INST(30, Alloca, AllocaInst) // Stack management
+HANDLE_MEMORY_INST(31, Load , LoadInst ) // Memory manipulation instrs
+HANDLE_MEMORY_INST(32, Store , StoreInst )
+HANDLE_MEMORY_INST(33, GetElementPtr, GetElementPtrInst)
+HANDLE_MEMORY_INST(34, Fence , FenceInst )
+HANDLE_MEMORY_INST(35, AtomicCmpXchg , AtomicCmpXchgInst )
+HANDLE_MEMORY_INST(36, AtomicRMW , AtomicRMWInst )
+ LAST_MEMORY_INST(36)
// Cast operators ...
// NOTE: The order matters here because CastInst::isEliminableCastPair
// NOTE: (see Instructions.cpp) encodes a table based on this ordering.
- 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)
+ FIRST_CAST_INST(37)
+HANDLE_CAST_INST(37, Trunc , TruncInst ) // Truncate integers
+HANDLE_CAST_INST(38, ZExt , ZExtInst ) // Zero extend integers
+HANDLE_CAST_INST(39, SExt , SExtInst ) // Sign extend integers
+HANDLE_CAST_INST(40, FPToUI , FPToUIInst ) // floating point -> UInt
+HANDLE_CAST_INST(41, FPToSI , FPToSIInst ) // floating point -> SInt
+HANDLE_CAST_INST(42, UIToFP , UIToFPInst ) // UInt -> floating point
+HANDLE_CAST_INST(43, SIToFP , SIToFPInst ) // SInt -> floating point
+HANDLE_CAST_INST(44, FPTrunc , FPTruncInst ) // Truncate floating point
+HANDLE_CAST_INST(45, FPExt , FPExtInst ) // Extend floating point
+HANDLE_CAST_INST(46, PtrToInt, PtrToIntInst) // Pointer -> Integer
+HANDLE_CAST_INST(47, IntToPtr, IntToPtrInst) // Integer -> Pointer
+HANDLE_CAST_INST(48, BitCast , BitCastInst ) // Type cast
+HANDLE_CAST_INST(49, AddrSpaceCast, AddrSpaceCastInst) // addrspace cast
+ LAST_CAST_INST(49)
+
+ FIRST_FUNCLETPAD_INST(50)
+HANDLE_FUNCLETPAD_INST(50, CleanupPad, CleanupPadInst)
+HANDLE_FUNCLETPAD_INST(51, CatchPad , CatchPadInst)
+ LAST_FUNCLETPAD_INST(51)
// Other operators...
FIRST_OTHER_INST(52)
@@ -178,8 +195,7 @@ 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)
+ LAST_OTHER_INST(65)
#undef FIRST_TERM_INST
#undef HANDLE_TERM_INST
@@ -197,6 +213,10 @@ HANDLE_OTHER_INST(66, CleanupPad, CleanupPadInst)
#undef HANDLE_CAST_INST
#undef LAST_CAST_INST
+#undef FIRST_FUNCLETPAD_INST
+#undef HANDLE_FUNCLETPAD_INST
+#undef LAST_FUNCLETPAD_INST
+
#undef FIRST_OTHER_INST
#undef HANDLE_OTHER_INST
#undef LAST_OTHER_INST
diff --git a/include/llvm/IR/Instruction.h b/include/llvm/IR/Instruction.h
index 77ba87c6b66..d7456a2c2fc 100644
--- a/include/llvm/IR/Instruction.h
+++ b/include/llvm/IR/Instruction.h
@@ -109,6 +109,7 @@ public:
bool isBinaryOp() const { return isBinaryOp(getOpcode()); }
bool isShift() { return isShift(getOpcode()); }
bool isCast() const { return isCast(getOpcode()); }
+ bool isFuncletPad() const { return isFuncletPad(getOpcode()); }
static const char* getOpcodeName(unsigned OpCode);
@@ -141,6 +142,11 @@ public:
return OpCode >= CastOpsBegin && OpCode < CastOpsEnd;
}
+ /// @brief Determine if the OpCode is one of the FuncletPadInst instructions.
+ static inline bool isFuncletPad(unsigned OpCode) {
+ return OpCode >= FuncletPadOpsBegin && OpCode < FuncletPadOpsEnd;
+ }
+
//===--------------------------------------------------------------------===//
// Metadata manipulation.
//===--------------------------------------------------------------------===//
@@ -386,10 +392,9 @@ public:
/// \brief Return true if the instruction is a variety of EH-block.
bool isEHPad() const {
switch (getOpcode()) {
+ case Instruction::CatchSwitch:
case Instruction::CatchPad:
- case Instruction::CatchEndPad:
case Instruction::CleanupPad:
- case Instruction::CleanupEndPad:
case Instruction::LandingPad:
case Instruction::TerminatePad:
return true;
@@ -478,6 +483,13 @@ public:
#include "llvm/IR/Instruction.def"
};
+ enum FuncletPadOps {
+#define FIRST_FUNCLETPAD_INST(N) FuncletPadOpsBegin = N,
+#define HANDLE_FUNCLETPAD_INST(N, OPC, CLASS) OPC = N,
+#define LAST_FUNCLETPAD_INST(N) FuncletPadOpsEnd = N+1
+#include "llvm/IR/Instruction.def"
+ };
+
enum OtherOps {
#define FIRST_OTHER_INST(N) OtherOpsBegin = N,
#define HANDLE_OTHER_INST(N, OPC, CLASS) OPC = N,
diff --git a/include/llvm/IR/Instructions.h b/include/llvm/IR/Instructions.h
index 84ab72138f0..e8171db4005 100644
--- a/include/llvm/IR/Instructions.h
+++ b/include/llvm/IR/Instructions.h
@@ -18,6 +18,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/CallingConv.h"
@@ -3819,181 +3820,176 @@ struct OperandTraits<ResumeInst> :
DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ResumeInst, Value)
//===----------------------------------------------------------------------===//
-// CatchEndPadInst Class
+// CatchSwitchInst Class
//===----------------------------------------------------------------------===//
+class CatchSwitchInst : public TerminatorInst {
+ void *operator new(size_t, unsigned) = delete;
+ /// ReservedSpace - The number of operands actually allocated. NumOperands is
+ /// the number actually in use.
+ unsigned ReservedSpace;
+ // Operand[0] = Outer scope
+ // Operand[1] = Unwind block destination
+ // Operand[n] = BasicBlock to go to on match
+ CatchSwitchInst(const CatchSwitchInst &CSI);
+ void init(Value *ParentPad, BasicBlock *UnwindDest, unsigned NumReserved);
+ void growOperands(unsigned Size);
+ // allocate space for exactly zero operands
+ void *operator new(size_t s) { return User::operator new(s); }
+ /// CatchSwitchInst ctor - Create a new switch instruction, specifying a
+ /// default destination. The number of additional handlers can be specified
+ /// here to make memory allocation more efficient.
+ /// This constructor can also autoinsert before another instruction.
+ CatchSwitchInst(Value *ParentPad, BasicBlock *UnwindDest,
+ unsigned NumHandlers, const Twine &NameStr,
+ Instruction *InsertBefore);
-class CatchEndPadInst : public TerminatorInst {
-private:
- CatchEndPadInst(const CatchEndPadInst &RI);
-
- void init(BasicBlock *UnwindBB);
- CatchEndPadInst(LLVMContext &C, BasicBlock *UnwindBB, unsigned Values,
- Instruction *InsertBefore = nullptr);
- CatchEndPadInst(LLVMContext &C, BasicBlock *UnwindBB, unsigned Values,
+ /// CatchSwitchInst ctor - Create a new switch instruction, specifying a
+ /// default destination. The number of additional handlers can be specified
+ /// here to make memory allocation more efficient.
+ /// This constructor also autoinserts at the end of the specified BasicBlock.
+ CatchSwitchInst(Value *ParentPad, BasicBlock *UnwindDest,
+ unsigned NumHandlers, const Twine &NameStr,
BasicBlock *InsertAtEnd);
protected:
// Note: Instruction needs to be a friend here to call cloneImpl.
friend class Instruction;
- CatchEndPadInst *cloneImpl() const;
+ CatchSwitchInst *cloneImpl() const;
public:
- static CatchEndPadInst *Create(LLVMContext &C, BasicBlock *UnwindBB = nullptr,
+ static CatchSwitchInst *Create(Value *ParentPad, BasicBlock *UnwindDest,
+ unsigned NumHandlers,
+ const Twine &NameStr = "",
Instruction *InsertBefore = nullptr) {
- unsigned Values = UnwindBB ? 1 : 0;
- return new (Values) CatchEndPadInst(C, UnwindBB, Values, InsertBefore);
+ return new CatchSwitchInst(ParentPad, UnwindDest, NumHandlers, NameStr,
+ InsertBefore);
}
- static CatchEndPadInst *Create(LLVMContext &C, BasicBlock *UnwindBB,
+ static CatchSwitchInst *Create(Value *ParentPad, BasicBlock *UnwindDest,
+ unsigned NumHandlers, const Twine &NameStr,
BasicBlock *InsertAtEnd) {
- unsigned Values = UnwindBB ? 1 : 0;
- return new (Values) CatchEndPadInst(C, UnwindBB, Values, InsertAtEnd);
+ return new CatchSwitchInst(ParentPad, UnwindDest, NumHandlers, NameStr,
+ InsertAtEnd);
}
/// Provide fast operand accessors
DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
+ // Accessor Methods for CatchSwitch stmt
+ Value *getParentPad() const { return getOperand(0); }
+ void setParentPad(Value *ParentPad) { setOperand(0, ParentPad); }
+
+ // Accessor Methods for CatchSwitch stmt
bool hasUnwindDest() const { return getSubclassDataFromInstruction() & 1; }
bool unwindsToCaller() const { return !hasUnwindDest(); }
-
- /// Convenience accessor. Returns null if there is no return value.
- unsigned getNumSuccessors() const { return hasUnwindDest() ? 1 : 0; }
-
BasicBlock *getUnwindDest() const {
- return hasUnwindDest() ? cast<BasicBlock>(Op<-1>()) : nullptr;
+ if (hasUnwindDest())
+ return cast<BasicBlock>(getOperand(1));
+ return nullptr;
}
- void setUnwindDest(BasicBlock *NewDest) {
- assert(NewDest);
- Op<-1>() = NewDest;
+ void setUnwindDest(BasicBlock *UnwindDest) {
+ assert(UnwindDest);
+ assert(hasUnwindDest());
+ setOperand(1, UnwindDest);
}
- // Methods for support type inquiry through isa, cast, and dyn_cast:
- static inline bool classof(const Instruction *I) {
- return (I->getOpcode() == Instruction::CatchEndPad);
- }
- static inline bool classof(const Value *V) {
- return isa<Instruction>(V) && classof(cast<Instruction>(V));
+ /// getNumHandlers - return the number of 'handlers' in this catchswitch
+ /// instruction, except the default handler
+ unsigned getNumHandlers() const {
+ if (hasUnwindDest())
+ return getNumOperands() - 2;
+ return getNumOperands() - 1;
}
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);
+ static BasicBlock *handler_helper(Value *V) { return cast<BasicBlock>(V); }
+ static const BasicBlock *handler_helper(const Value *V) {
+ return cast<BasicBlock>(V);
}
-};
-
-template <>
-struct OperandTraits<CatchEndPadInst>
- : public VariadicOperandTraits<CatchEndPadInst> {};
-
-DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CatchEndPadInst, Value)
-
-//===----------------------------------------------------------------------===//
-// CatchPadInst Class
-//===----------------------------------------------------------------------===//
-
-class CatchPadInst : public TerminatorInst {
-private:
- void init(BasicBlock *IfNormal, BasicBlock *IfException,
- ArrayRef<Value *> Args, const Twine &NameStr);
-
- CatchPadInst(const CatchPadInst &CPI);
-
- explicit CatchPadInst(BasicBlock *IfNormal, BasicBlock *IfException,
- ArrayRef<Value *> Args, unsigned Values,
- const Twine &NameStr, Instruction *InsertBefore);
- explicit CatchPadInst(BasicBlock *IfNormal, BasicBlock *IfException,
- ArrayRef<Value *> Args, unsigned Values,
- const Twine &NameStr, BasicBlock *InsertAtEnd);
-
-protected:
- // Note: Instruction needs to be a friend here to call cloneImpl.
- friend class Instruction;
- CatchPadInst *cloneImpl() const;
public:
- static CatchPadInst *Create(BasicBlock *IfNormal, BasicBlock *IfException,
- ArrayRef<Value *> Args, const Twine &NameStr = "",
- Instruction *InsertBefore = nullptr) {
- unsigned Values = unsigned(Args.size()) + 2;
- return new (Values) CatchPadInst(IfNormal, IfException, Args, Values,
- NameStr, InsertBefore);
- }
- static CatchPadInst *Create(BasicBlock *IfNormal, BasicBlock *IfException,
- ArrayRef<Value *> Args, const Twine &NameStr,
- BasicBlock *InsertAtEnd) {
- unsigned Values = unsigned(Args.size()) + 2;
- return new (Values)
- CatchPadInst(IfNormal, IfException, Args, Values, NameStr, InsertAtEnd);
- }
+ typedef std::pointer_to_unary_function<Value *, BasicBlock *> DerefFnTy;
+ typedef mapped_iterator<op_iterator, DerefFnTy> handler_iterator;
+ typedef iterator_range<handler_iterator> handler_range;
- /// Provide fast operand accessors
- DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
- /// getNumArgOperands - Return the number of catchpad arguments.
- ///
- unsigned getNumArgOperands() const { return getNumOperands() - 2; }
+ typedef std::pointer_to_unary_function<const Value *, const BasicBlock *>
+ ConstDerefFnTy;
+ typedef mapped_iterator<const_op_iterator, ConstDerefFnTy> const_handler_iterator;
+ typedef iterator_range<const_handler_iterator> const_handler_range;
- /// getArgOperand/setArgOperand - Return/set the i-th catchpad argument.
- ///
- Value *getArgOperand(unsigned i) const { return getOperand(i); }
- void setArgOperand(unsigned i, Value *v) { setOperand(i, v); }
+ /// Returns an iterator that points to the first handler in CatchSwitchInst.
+ handler_iterator handler_begin() {
+ op_iterator It = op_begin() + 1;
+ if (hasUnwindDest())
+ ++It;
+ return handler_iterator(It, DerefFnTy(handler_helper));
+ }
+ /// Returns an iterator that points to the first handler in the
+ /// CatchSwitchInst.
+ const_handler_iterator handler_begin() const {
+ const_op_iterator It = op_begin() + 1;
+ if (hasUnwindDest())
+ ++It;
+ return const_handler_iterator(It, ConstDerefFnTy(handler_helper));
+ }
- /// arg_operands - iteration adapter for range-for loops.
- iterator_range<op_iterator> arg_operands() {
- return make_range(op_begin(), op_end() - 2);
+ /// Returns a read-only iterator that points one past the last
+ /// handler in the CatchSwitchInst.
+ handler_iterator handler_end() {
+ return handler_iterator(op_end(), DerefFnTy(handler_helper));
+ }
+ /// Returns an iterator that points one past the last handler in the
+ /// CatchSwitchInst.
+ const_handler_iterator handler_end() const {
+ return const_handler_iterator(op_end(), ConstDerefFnTy(handler_helper));
}
- /// arg_operands - iteration adapter for range-for loops.
- iterator_range<const_op_iterator> arg_operands() const {
- return make_range(op_begin(), op_end() - 2);
+ /// handlers - iteration adapter for range-for loops.
+ handler_range handlers() {
+ return make_range(handler_begin(), handler_end());
}
- /// \brief Wrappers for getting the \c Use of a catchpad argument.
- const Use &getArgOperandUse(unsigned i) const { return getOperandUse(i); }
- Use &getArgOperandUse(unsigned i) { return getOperandUse(i); }
+ /// handlers - iteration adapter for range-for loops.
+ const_handler_range handlers() const {
+ return make_range(handler_begin(), handler_end());
+ }
- // get*Dest - Return the destination basic blocks...
- BasicBlock *getNormalDest() const { return cast<BasicBlock>(Op<-2>()); }
- BasicBlock *getUnwindDest() const { return cast<BasicBlock>(Op<-1>()); }
- void setNormalDest(BasicBlock *B) { Op<-2>() = B; }
- void setUnwindDest(BasicBlock *B) { Op<-1>() = B; }
+ /// addHandler - Add an entry to the switch instruction...
+ /// Note:
+ /// This action invalidates handler_end(). Old handler_end() iterator will
+ /// point to the added handler.
+ void addHandler(BasicBlock *Dest);
- BasicBlock *getSuccessor(unsigned i) const {
- assert(i < 2 && "Successor # out of range for catchpad!");
- return i == 0 ? getNormalDest() : getUnwindDest();
+ unsigned getNumSuccessors() const { return getNumOperands() - 1; }
+ BasicBlock *getSuccessor(unsigned Idx) const {
+ assert(Idx < getNumSuccessors() &&
+ "Successor # out of range for catchswitch!");
+ return cast<BasicBlock>(getOperand(Idx + 1));
}
-
- void setSuccessor(unsigned idx, BasicBlock *NewSucc) {
- assert(idx < 2 && "Successor # out of range for catchpad!");
- *(&Op<-2>() + idx) = NewSucc;
+ void setSuccessor(unsigned Idx, BasicBlock *NewSucc) {
+ assert(Idx < getNumSuccessors() &&
+ "Successor # out of range for catchswitch!");
+ setOperand(Idx + 1, NewSucc);
}
- unsigned getNumSuccessors() const { return 2; }
-
// Methods for support type inquiry through isa, cast, and dyn_cast:
static inline bool classof(const Instruction *I) {
- return I->getOpcode() == Instruction::CatchPad;
+ return I->getOpcode() == Instruction::CatchSwitch;
}
static inline bool classof(const Value *V) {
return isa<Instruction>(V) && classof(cast<Instruction>(V));
}
private:
- BasicBlock *getSuccessorV(unsigned idx) const override;
+ BasicBlock *getSuccessorV(unsigned Idx) const override;
unsigned getNumSuccessorsV() const override;
- void setSuccessorV(unsigned idx, BasicBlock *B) override;
+ void setSuccessorV(unsigned Idx, BasicBlock *B) override;
};
template <>
-struct OperandTraits<CatchPadInst>
- : public VariadicOperandTraits<CatchPadInst, /*MINARITY=*/2> {};
+struct OperandTraits<CatchSwitchInst> : public HungoffOperandTraits<2> {};
-DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CatchPadInst, Value)
+DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CatchSwitchInst, Value)
//===----------------------------------------------------------------------===//
// TerminatePadInst Class
@@ -4001,14 +3997,14 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CatchPadInst, Value)
class TerminatePadInst : public TerminatorInst {
private:
- void init(BasicBlock *BB, ArrayRef<Value *> Args);
+ void init(Value *ParentPad, BasicBlock *BB, ArrayRef<Value *> Args);
TerminatePadInst(const TerminatePadInst &TPI);
- explicit TerminatePadInst(LLVMContext &C, BasicBlock *BB,
+ explicit TerminatePadInst(Value *ParentPad, BasicBlock *BB,
ArrayRef<Value *> Args, unsigned Values,
Instruction *InsertBefore);
- explicit TerminatePadInst(LLVMContext &C, BasicBlock *BB,
+ explicit TerminatePadInst(Value *ParentPad, BasicBlock *BB,
ArrayRef<Value *> Args, unsigned Values,
BasicBlock *InsertAtEnd);
@@ -4018,21 +4014,23 @@ protected:
TerminatePadInst *cloneImpl() const;
public:
- static TerminatePadInst *Create(LLVMContext &C, BasicBlock *BB = nullptr,
+ static TerminatePadInst *Create(Value *ParentPad, BasicBlock *BB = nullptr,
ArrayRef<Value *> Args = None,
Instruction *InsertBefore = nullptr) {
- unsigned Values = unsigned(Args.size());
+ unsigned Values = unsigned(Args.size()) + 1;
if (BB)
++Values;
- return new (Values) TerminatePadInst(C, BB, Args, Values, InsertBefore);
+ return new (Values)
+ TerminatePadInst(ParentPad, BB, Args, Values, InsertBefore);
}
- static TerminatePadInst *Create(LLVMContext &C, BasicBlock *BB,
+ static TerminatePadInst *Create(Value *ParentPad, BasicBlock *BB,
ArrayRef<Value *> Args,
BasicBlock *InsertAtEnd) {
- unsigned Values = unsigned(Args.size());
+ unsigned Values = unsigned(Args.size()) + 1;
if (BB)
++Values;
- return new (Values) TerminatePadInst(C, BB, Args, Values, InsertAtEnd);
+ return new (Values)
+ TerminatePadInst(ParentPad, BB, Args, Values, InsertAtEnd);
}
/// Provide fast operand accessors
@@ -4046,8 +4044,15 @@ public:
unsigned getNumArgOperands() const {
unsigned NumOperands = getNumOperands();
if (hasUnwindDest())
- return NumOperands - 1;
- return NumOperands;
+ return NumOperands - 2;
+ return NumOperands - 1;
+ }
+
+ /// Convenience accessors
+ Value *getParentPad() const { return Op<-1>(); }
+ void setParentPad(Value *ParentPad) {
+ assert(ParentPad);
+ Op<-1>() = ParentPad;
}
/// getArgOperand/setArgOperand - Return/set the i-th terminatepad argument.
@@ -4055,26 +4060,29 @@ public:
Value *getArgOperand(unsigned i) const { return getOperand(i); }
void setArgOperand(unsigned i, Value *v) { setOperand(i, v); }
+ const_op_iterator arg_begin() const { return op_begin(); }
+ op_iterator arg_begin() { return op_begin(); }
+
const_op_iterator arg_end() const {
if (hasUnwindDest())
- return op_end() - 1;
- return op_end();
+ return op_end() - 2;
+ return op_end() - 1;
}
op_iterator arg_end() {
if (hasUnwindDest())
- return op_end() - 1;
- return op_end();
+ return op_end() - 2;
+ return op_end() - 1;
}
/// arg_operands - iteration adapter for range-for loops.
iterator_range<op_iterator> arg_operands() {
- return make_range(op_begin(), arg_end());
+ return make_range(arg_begin(), arg_end());
}
/// arg_operands - iteration adapter for range-for loops.
iterator_range<const_op_iterator> arg_operands() const {
- return make_range(op_begin(), arg_end());
+ return make_range(arg_begin(), arg_end());
}
/// \brief Wrappers for getting the \c Use of a terminatepad argument.
@@ -4085,11 +4093,11 @@ public:
BasicBlock *getUnwindDest() const {
if (!hasUnwindDest())
return nullptr;
- return cast<BasicBlock>(Op<-1>());
+ return cast<BasicBlock>(Op<-2>());
}
void setUnwindDest(BasicBlock *B) {
assert(B && hasUnwindDest());
- Op<-1>() = B;
+ Op<-2>() = B;
}
unsigned getNumSuccessors() const { return hasUnwindDest() ? 1 : 0; }
@@ -4121,40 +4129,37 @@ struct OperandTraits<TerminatePadInst>
DEFINE_TRANSPARENT_OPERAND_ACCESSORS(TerminatePadInst, Value)
//===----------------------------------------------------------------------===//
-// CleanupPadInst Class
+// CleanupPadInst Class
//===----------------------------------------------------------------------===//
-
-class CleanupPadInst : public Instruction {
+class CleanupPadInst : public FuncletPadInst {
private:
- void init(ArrayRef<Value *> Args, const Twine &NameStr);
-
- CleanupPadInst(const CleanupPadInst &CPI);
-
- explicit CleanupPadInst(LLVMContext &C, ArrayRef<Value *> Args,
- const Twine &NameStr, Instruction *InsertBefore);
- explicit CleanupPadInst(LLVMContext &C, ArrayRef<Value *> Args,
- const Twine &NameStr, BasicBlock *InsertAtEnd);
-
-protected:
- // Note: Instruction needs to be a friend here to call cloneImpl.
- friend class Instruction;
- CleanupPadInst *cloneImpl() const;
+ explicit CleanupPadInst(Value *ParentPad, ArrayRef<Value *> Args,
+ unsigned Values, const Twine &NameStr,
+ Instruction *InsertBefore)
+ : FuncletPadInst(Instruction::CleanupPad, ParentPad, Args, Values,
+ NameStr, InsertBefore) {}
+ explicit CleanupPadInst(Value *ParentPad, ArrayRef<Value *> Args,
+ unsigned Values, const Twine &NameStr,
+ BasicBlock *InsertAtEnd)
+ : FuncletPadInst(Instruction::CleanupPad, ParentPad, Args, Values,
+ NameStr, InsertAtEnd) {}
public:
- static CleanupPadInst *Create(LLVMContext &C, ArrayRef<Value *> Args,
+ static CleanupPadInst *Create(Value *ParentPad, ArrayRef<Value *> Args = None,
const Twine &NameStr = "",
Instruction *InsertBefore = nullptr) {
- return new (Args.size()) CleanupPadInst(C, Args, NameStr, InsertBefore);
+ unsigned Values = 1 + Args.size();
+ return new (Values)
+ CleanupPadInst(ParentPad, Args, Values, NameStr, InsertBefore);
}
- static CleanupPadInst *Create(LLVMContext &C, ArrayRef<Value *> Args,
+ static CleanupPadInst *Create(Value *ParentPad, ArrayRef<Value *> Args,
const Twine &NameStr, BasicBlock *InsertAtEnd) {
- return new (Args.size()) CleanupPadInst(C, Args, NameStr, InsertAtEnd);
+ unsigned Values = 1 + Args.size();
+ return new (Values)
+ CleanupPadInst(ParentPad, Args, Values, NameStr, InsertAtEnd);
}
- /// Provide fast operand accessors
- DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
-
- // Methods for support type inquiry through isa, cast, and dyn_cast:
+ /// \brief Methods for support type inquiry through isa, cast, and dyn_cast:
static inline bool classof(const Instruction *I) {
return I->getOpcode() == Instruction::CleanupPad;
}
@@ -4163,11 +4168,54 @@ public:
}
};
-template <>
-struct OperandTraits<CleanupPadInst>
- : public VariadicOperandTraits<CleanupPadInst, /*MINARITY=*/0> {};
+//===----------------------------------------------------------------------===//
+// CatchPadInst Class
+//===----------------------------------------------------------------------===//
+class CatchPadInst : public FuncletPadInst {
+private:
+ explicit CatchPadInst(Value *CatchSwitch, ArrayRef<Value *> Args,
+ unsigned Values, const Twine &NameStr,
+ Instruction *InsertBefore)
+ : FuncletPadInst(Instruction::CatchPad, CatchSwitch, Args, Values,
+ NameStr, InsertBefore) {}
+ explicit CatchPadInst(Value *CatchSwitch, ArrayRef<Value *> Args,
+ unsigned Values, const Twine &NameStr,
+ BasicBlock *InsertAtEnd)
+ : FuncletPadInst(Instruction::CatchPad, CatchSwitch, Args, Values,
+ NameStr, InsertAtEnd) {}
-DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CleanupPadInst, Value)
+public:
+ static CatchPadInst *Create(Value *CatchSwitch, ArrayRef<Value *> Args,
+ const Twine &NameStr = "",
+ Instruction *InsertBefore = nullptr) {
+ unsigned Values = 1 + Args.size();
+ return new (Values)
+ CatchPadInst(CatchSwitch, Args, Values, NameStr, InsertBefore);
+ }
+ static CatchPadInst *Create(Value *CatchSwitch, ArrayRef<Value *> Args,
+ const Twine &NameStr, BasicBlock *InsertAtEnd) {
+ unsigned Values = 1 + Args.size();
+ return new (Values)
+ CatchPadInst(CatchSwitch, Args, Values, NameStr, InsertAtEnd);
+ }
+
+ /// Convenience accessors
+ CatchSwitchInst *getCatchSwitch() const {
+ return cast<CatchSwitchInst>(Op<-1>());
+ }
+ void setCatchSwitch(Value *CatchSwitch) {
+ assert(CatchSwitch);
+ Op<-1>() = CatchSwitch;
+ }
+
+ /// \brief Methods for support type inquiry through isa, cast, and dyn_cast:
+ static inline bool classof(const Instruction *I) {
+ return I->getOpcode() == Instruction::CatchPad;
+ }
+ static inline bool classof(const Value *V) {
+ return isa<Instruction>(V) && classof(cast<Instruction>(V));
+ }
+};
//===----------------------------------------------------------------------===//
// CatchReturnInst Class
@@ -4176,11 +4224,9 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CleanupPadInst, Value)
class CatchReturnInst : public TerminatorInst {
CatchReturnInst(const CatchReturnInst &RI);
- void init(CatchPadInst *CatchPad, BasicBlock *BB);
- CatchReturnInst(CatchPadInst *CatchPad, BasicBlock *BB,
- Instruction *InsertBefore);
- CatchReturnInst(CatchPadInst *CatchPad, BasicBlock *BB,
- BasicBlock *InsertAtEnd);
+ void init(Value *CatchPad, BasicBlock *BB);
+ CatchReturnInst(Value *CatchPad, BasicBlock *BB, Instruction *InsertBefore);
+ CatchReturnInst(Value *CatchPad, BasicBlock *BB, BasicBlock *InsertAtEnd);
protected:
// Note: Instruction needs to be a friend here to call cloneImpl.
@@ -4188,13 +4234,13 @@ protected:
CatchReturnInst *cloneImpl() const;
public:
- static CatchReturnInst *Create(CatchPadInst *CatchPad, BasicBlock *BB,
+ static CatchReturnInst *Create(Value *CatchPad, BasicBlock *BB,
Instruction *InsertBefore = nullptr) {
assert(CatchPad);
assert(BB);
return new (2) CatchReturnInst(CatchPad, BB, InsertBefore);
}
- static CatchReturnInst *Create(CatchPadInst *CatchPad, BasicBlock *BB,
+ static CatchReturnInst *Create(Value *CatchPad, BasicBlock *BB,
BasicBlock *InsertAtEnd) {
assert(CatchPad);
assert(BB);
@@ -4218,6 +4264,10 @@ public:
}
unsigned getNumSuccessors() const { return 1; }
+ Value *getParentPad() const {
+ return getCatchPad()->getCatchSwitch()->getParentPad();
+ }
+
// Methods for support type inquiry through isa, cast, and dyn_cast:
static inline bool classof(const Instruction *I) {
return (I->getOpcode() == Instruction::CatchRet);
@@ -4239,93 +4289,6 @@ struct OperandTraits<CatchReturnInst>
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
//===----------------------------------------------------------------------===//
@@ -4333,11 +4296,11 @@ class CleanupReturnInst : public TerminatorInst {
private:
CleanupReturnInst(const CleanupReturnInst &RI);
- void init(CleanupPadInst *CleanupPad, BasicBlock *UnwindBB);
- CleanupReturnInst(CleanupPadInst *CleanupPad, BasicBlock *UnwindBB,
- unsigned Values, Instruction *InsertBefore = nullptr);
- CleanupReturnInst(CleanupPadInst *CleanupPad, BasicBlock *UnwindBB,
- unsigned Values, BasicBlock *InsertAtEnd);
+ void init(Value *CleanupPad, BasicBlock *UnwindBB);
+ CleanupReturnInst(Value *CleanupPad, BasicBlock *UnwindBB, unsigned Values,
+ Instruction *InsertBefore = nullptr);
+ CleanupReturnInst(Value *CleanupPad, BasicBlock *UnwindBB, unsigned Values,
+ BasicBlock *InsertAtEnd);
protected:
// Note: Instruction needs to be a friend here to call cloneImpl.
@@ -4345,7 +4308,7 @@ protected:
CleanupReturnInst *cloneImpl() const;
public:
- static CleanupReturnInst *Create(CleanupPadInst *CleanupPad,
+ static CleanupReturnInst *Create(Value *CleanupPad,
BasicBlock *UnwindBB = nullptr,
Instruction *InsertBefore = nullptr) {
assert(CleanupPad);
@@ -4355,8 +4318,7 @@ public:
return new (Values)
CleanupReturnInst(CleanupPad, UnwindBB, Values, InsertBefore);
}
- static CleanupReturnInst *Create(CleanupPadInst *CleanupPad,
- BasicBlock *UnwindBB,
+ static CleanupReturnInst *Create(Value *CleanupPad, BasicBlock *UnwindBB,
BasicBlock *InsertAtEnd) {
assert(CleanupPad);
unsigned Values = 1;
@@ -4374,22 +4336,22 @@ public:
/// Convenience accessor.
CleanupPadInst *getCleanupPad() const {
- return cast<CleanupPadInst>(Op<-1>());
+ return cast<CleanupPadInst>(Op<0>());
}
void setCleanupPad(CleanupPadInst *CleanupPad) {
assert(CleanupPad);
- Op<-1>() = CleanupPad;
+ Op<0>() = CleanupPad;
}
unsigned getNumSuccessors() const { return hasUnwindDest() ? 1 : 0; }
BasicBlock *getUnwindDest() const {
- return hasUnwindDest() ? cast<BasicBlock>(Op<-2>()) : nullptr;
+ return hasUnwindDest() ? cast<BasicBlock>(Op<1>()) : nullptr;
}
void setUnwindDest(BasicBlock *NewDest) {
assert(NewDest);
assert(hasUnwindDest());
- Op<-2>() = NewDest;
+ Op<1>() = NewDest;
}
// Methods for support type inquiry through isa, cast, and dyn_cast:
diff --git a/include/llvm/Transforms/Utils/Local.h b/include/llvm/Transforms/Utils/Local.h
index 1d707a1e530..6fe1a03919e 100644
--- a/include/llvm/Transforms/Utils/Local.h
+++ b/include/llvm/Transforms/Utils/Local.h
@@ -289,8 +289,8 @@ bool replaceDbgDeclareForAlloca(AllocaInst *AI, Value *NewAllocaAddress,
DIBuilder &Builder, bool Deref, int Offset = 0);
/// Replace 'BB's terminator with one that does not have an unwind successor
-/// block. Rewrites `invoke` to `call`, `catchendpad unwind label %foo` to
-/// `catchendpad unwind to caller`, etc. Updates any PHIs in unwind successor.
+/// block. Rewrites `invoke` to `call`, `terminatepad unwind label %foo` to
+/// `terminatepad unwind to caller`, etc. Updates any PHIs in unwind successor.
///
/// \param BB Block whose terminator will be replaced. Its terminator must
/// have an unwind successor.
diff --git a/lib/Analysis/CaptureTracking.cpp b/lib/Analysis/CaptureTracking.cpp
index c717a8ee2e6..1add2fa7756 100644
--- a/lib/Analysis/CaptureTracking.cpp
+++ b/lib/Analysis/CaptureTracking.cpp
@@ -80,12 +80,11 @@ namespace {
if (BB == BeforeHere->getParent()) {
// 'I' dominates 'BeforeHere' => not safe to prune.
//
- // The value defined by an invoke/catchpad dominates an instruction only
+ // The value defined by an invoke dominates an instruction only
// if it dominates every instruction in UseBB. A PHI is dominated only
// if the instruction dominates every possible use in the UseBB. Since
// UseBB == BB, avoid pruning.
- if (isa<InvokeInst>(BeforeHere) || isa<CatchPadInst>(BeforeHere) ||
- isa<PHINode>(I) || I == BeforeHere)
+ if (isa<InvokeInst>(BeforeHere) || isa<PHINode>(I) || I == BeforeHere)
return false;
if (!OrderedBB->dominates(BeforeHere, I))
return false;
diff --git a/lib/Analysis/EHPersonalities.cpp b/lib/Analysis/EHPersonalities.cpp
index 1d1b5fe11f6..c95fcee13b8 100644
--- a/lib/Analysis/EHPersonalities.cpp
+++ b/lib/Analysis/EHPersonalities.cpp
@@ -9,7 +9,11 @@
#include "llvm/Analysis/EHPersonalities.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/IR/CFG.h"
+#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/Support/Debug.h"
using namespace llvm;
/// See if the given exception handling personality function is one that we
@@ -39,3 +43,64 @@ bool llvm::canSimplifyInvokeNoUnwind(const Function *F) {
// implies that the function does not throw synchronous exceptions.
return !isAsynchronousEHPersonality(Personality);
}
+
+DenseMap<BasicBlock *, ColorVector> llvm::colorEHFunclets(Function &F) {
+ SmallVector<std::pair<BasicBlock *, BasicBlock *>, 16> Worklist;
+ BasicBlock *EntryBlock = &F.getEntryBlock();
+ DenseMap<BasicBlock *, ColorVector> BlockColors;
+
+ // Build up the color map, which maps each block to its set of 'colors'.
+ // For any block B the "colors" of B are the set of funclets F (possibly
+ // including a root "funclet" representing the main function) such that
+ // F will need to directly contain B or a copy of B (where the term "directly
+ // contain" is used to distinguish from being "transitively contained" in
+ // a nested funclet).
+ //
+ // Note: Despite not being funclets in the truest sense, terminatepad and
+ // catchswitch are considered to belong to their own funclet for the purposes
+ // of coloring.
+
+ DEBUG_WITH_TYPE("winehprepare-coloring", dbgs() << "\nColoring funclets for "
+ << F.getName() << "\n");
+
+ Worklist.push_back({EntryBlock, EntryBlock});
+
+ while (!Worklist.empty()) {
+ BasicBlock *Visiting;
+ BasicBlock *Color;
+ std::tie(Visiting, Color) = Worklist.pop_back_val();
+ DEBUG_WITH_TYPE("winehprepare-coloring",
+ dbgs() << "Visiting " << Visiting->getName() << ", "
+ << Color->getName() << "\n");
+ Instruction *VisitingHead = Visiting->getFirstNonPHI();
+ if (VisitingHead->isEHPad()) {
+ // Mark this funclet head as a member of itself.
+ Color = Visiting;
+ }
+ // Note that this is a member of the given color.
+ ColorVector &Colors = BlockColors[Visiting];
+ if (std::find(Colors.begin(), Colors.end(), Color) == Colors.end())
+ Colors.push_back(Color);
+ else
+ continue;
+
+ DEBUG_WITH_TYPE("winehprepare-coloring",
+ dbgs() << " Assigned color \'" << Color->getName()
+ << "\' to block \'" << Visiting->getName()
+ << "\'.\n");
+
+ BasicBlock *SuccColor = Color;
+ TerminatorInst *Terminator = Visiting->getTerminator();
+ if (auto *CatchRet = dyn_cast<CatchReturnInst>(Terminator)) {
+ Value *ParentPad = CatchRet->getParentPad();
+ if (isa<ConstantTokenNone>(ParentPad))
+ SuccColor = EntryBlock;
+ else
+ SuccColor = cast<Instruction>(ParentPad)->getParent();
+ }
+
+ for (BasicBlock *Succ : successors(Visiting))
+ Worklist.push_back({Succ, SuccColor});
+ }
+ return BlockColors;
+}
diff --git a/lib/Analysis/InstructionSimplify.cpp b/lib/Analysis/InstructionSimplify.cpp
index 0bd18c1a35c..db17d886e4b 100644
--- a/lib/Analysis/InstructionSimplify.cpp
+++ b/lib/Analysis/InstructionSimplify.cpp
@@ -122,10 +122,10 @@ static bool ValueDominatesPHI(Value *V, PHINode *P, const DominatorTree *DT) {
return DT->dominates(I, P);
}
- // Otherwise, if the instruction is in the entry block, and is not an invoke,
- // and is not a catchpad, then it obviously dominates all phi nodes.
+ // Otherwise, if the instruction is in the entry block and is not an invoke,
+ // then it obviously dominates all phi nodes.
if (I->getParent() == &I->getParent()->getParent()->getEntryBlock() &&
- !isa<InvokeInst>(I) && !isa<CatchPadInst>(I))
+ !isa<InvokeInst>(I))
return true;
return false;
diff --git a/lib/Analysis/LoopInfo.cpp b/lib/Analysis/LoopInfo.cpp
index 67a82b192e5..07fd6a2ae70 100644
--- a/lib/Analysis/LoopInfo.cpp
+++ b/lib/Analysis/LoopInfo.cpp
@@ -227,9 +227,15 @@ bool Loop::isSafeToClone() const {
if (isa<IndirectBrInst>((*I)->getTerminator()))
return false;
- if (const InvokeInst *II = dyn_cast<InvokeInst>((*I)->getTerminator()))
+ if (const InvokeInst *II = dyn_cast<InvokeInst>((*I)->getTerminator())) {
if (II->cannotDuplicate())
return false;
+ // Return false if any loop blocks contain invokes to EH-pads other than
+ // landingpads; we don't know how to split those edges yet.
+ auto *FirstNonPHI = II->getUnwindDest()->getFirstNonPHI();
+ if (FirstNonPHI->isEHPad() && !isa<LandingPadInst>(FirstNonPHI))
+ return false;
+ }
for (BasicBlock::iterator BI = (*I)->begin(), BE = (*I)->end(); BI != BE; ++BI) {
if (const CallInst *CI = dyn_cast<CallInst>(BI)) {
diff --git a/lib/Analysis/ScalarEvolutionExpander.cpp b/lib/Analysis/ScalarEvolutionExpander.cpp
index abfcfbafb32..bcbf35b046b 100644
--- a/lib/Analysis/ScalarEvolutionExpander.cpp
+++ b/lib/Analysis/ScalarEvolutionExpander.cpp
@@ -91,22 +91,16 @@ static BasicBlock::iterator findInsertPointAfter(Instruction *I,
BasicBlock::iterator IP = ++I->getIterator();
if (auto *II = dyn_cast<InvokeInst>(I))
IP = II->getNormalDest()->begin();
- if (auto *CPI = dyn_cast<CatchPadInst>(I))
- IP = CPI->getNormalDest()->begin();
while (isa<PHINode>(IP))
++IP;
while (IP->isEHPad()) {
- if (isa<LandingPadInst>(IP) || isa<CleanupPadInst>(IP)) {
+ if (isa<FuncletPadInst>(IP) || isa<LandingPadInst>(IP)) {
++IP;
} else if (auto *TPI = dyn_cast<TerminatePadInst>(IP)) {
IP = TPI->getUnwindDest()->getFirstNonPHI()->getIterator();
- } else if (auto *CEPI = dyn_cast<CatchEndPadInst>(IP)) {
- IP = CEPI->getUnwindDest()->getFirstNonPHI()->getIterator();
- } else if (auto *CEPI = dyn_cast<CleanupEndPadInst>(IP)) {
- IP = CEPI->getUnwindDest()->getFirstNonPHI()->getIterator();
- } else if (isa<CatchPadInst>(IP)) {
+ } else if (isa<CatchSwitchInst>(IP)) {
IP = MustDominate->getFirstInsertionPt();
} else {
llvm_unreachable("unexpected eh pad!");
diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp
index b2a1034eeaa..4a228c30a93 100644
--- a/lib/Analysis/ValueTracking.cpp
+++ b/lib/Analysis/ValueTracking.cpp
@@ -3431,11 +3431,10 @@ bool llvm::isSafeToSpeculativelyExecute(const Value *V,
case Instruction::AtomicCmpXchg:
case Instruction::LandingPad:
case Instruction::Resume:
+ case Instruction::CatchSwitch:
case Instruction::CatchPad:
- 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
diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp
index db90f78b318..59b7db0ea4c 100644
--- a/lib/AsmParser/LLLexer.cpp
+++ b/lib/AsmParser/LLLexer.cpp
@@ -526,6 +526,8 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(none);
KEYWORD(to);
KEYWORD(caller);
+ KEYWORD(within);
+ KEYWORD(from);
KEYWORD(tail);
KEYWORD(musttail);
KEYWORD(notail);
@@ -759,11 +761,10 @@ lltok::Kind LLLexer::LexIdentifier() {
INSTKEYWORD(landingpad, LandingPad);
INSTKEYWORD(cleanupret, CleanupRet);
INSTKEYWORD(catchret, CatchRet);
+ INSTKEYWORD(catchswitch, CatchSwitch);
INSTKEYWORD(catchpad, CatchPad);
INSTKEYWORD(terminatepad, TerminatePad);
INSTKEYWORD(cleanuppad, CleanupPad);
- INSTKEYWORD(catchendpad, CatchEndPad);
- INSTKEYWORD(cleanupendpad, CleanupEndPad);
#undef INSTKEYWORD
#define DWKEYWORD(TYPE, TOKEN) \
diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp
index b5cbee5085b..2e411733e27 100644
--- a/lib/AsmParser/LLParser.cpp
+++ b/lib/AsmParser/LLParser.cpp
@@ -2315,7 +2315,7 @@ bool LLParser::PerFunctionState::FinishFunction() {
/// forward reference record if needed. This can return null if the value
/// exists but does not have the right type.
Value *LLParser::PerFunctionState::GetVal(const std::string &Name, Type *Ty,
- LocTy Loc, OperatorConstraint OC) {
+ LocTy Loc) {
// Look this name up in the normal function symbol table.
Value *Val = F.getValueSymbolTable().lookup(Name);
@@ -2329,24 +2329,6 @@ Value *LLParser::PerFunctionState::GetVal(const std::string &Name, Type *Ty,
// If we have the value in the symbol table or fwd-ref table, return it.
if (Val) {
- // Check operator constraints.
- switch (OC) {
- case OC_None:
- // no constraint
- break;
- case OC_CatchPad:
- if (!isa<CatchPadInst>(Val)) {
- P.Error(Loc, "'%" + Name + "' is not a catchpad");
- return nullptr;
- }
- break;
- case OC_CleanupPad:
- if (!isa<CleanupPadInst>(Val)) {
- P.Error(Loc, "'%" + Name + "' is not a cleanuppad");
- return nullptr;
- }
- break;
- }
if (Val->getType() == Ty) return Val;
if (Ty->isLabelTy())
P.Error(Loc, "'%" + Name + "' is not a basic block");
@@ -2365,30 +2347,16 @@ Value *LLParser::PerFunctionState::GetVal(const std::string &Name, Type *Ty,
// Otherwise, create a new forward reference for this value and remember it.
Value *FwdVal;
if (Ty->isLabelTy()) {
- assert(!OC);
FwdVal = BasicBlock::Create(F.getContext(), Name, &F);
- } else if (!OC) {
- FwdVal = new Argument(Ty, Name);
} else {
- switch (OC) {
- case OC_CatchPad:
- FwdVal = CatchPadInst::Create(&F.getEntryBlock(), &F.getEntryBlock(), {},
- Name);
- break;
- case OC_CleanupPad:
- FwdVal = CleanupPadInst::Create(F.getContext(), {}, Name);
- break;
- default:
- llvm_unreachable("unexpected constraint");
- }
+ FwdVal = new Argument(Ty, Name);
}
ForwardRefVals[Name] = std::make_pair(FwdVal, Loc);
return FwdVal;
}
-Value *LLParser::PerFunctionState::GetVal(unsigned ID, Type *Ty, LocTy Loc,
- OperatorConstraint OC) {
+Value *LLParser::PerFunctionState::GetVal(unsigned ID, Type *Ty, LocTy Loc) {
// Look this name up in the normal function symbol table.
Value *Val = ID < NumberedVals.size() ? NumberedVals[ID] : nullptr;
@@ -2402,24 +2370,6 @@ Value *LLParser::PerFunctionState::GetVal(unsigned ID, Type *Ty, LocTy Loc,
// If we have the value in the symbol table or fwd-ref table, return it.
if (Val) {
- // Check operator constraint.
- switch (OC) {
- case OC_None:
- // no constraint
- break;
- case OC_CatchPad:
- if (!isa<CatchPadInst>(Val)) {
- P.Error(Loc, "'%" + Twine(ID) + "' is not a catchpad");
- return nullptr;
- }
- break;
- case OC_CleanupPad:
- if (!isa<CleanupPadInst>(Val)) {
- P.Error(Loc, "'%" + Twine(ID) + "' is not a cleanuppad");
- return nullptr;
- }
- break;
- }
if (Val->getType() == Ty) return Val;
if (Ty->isLabelTy())
P.Error(Loc, "'%" + Twine(ID) + "' is not a basic block");
@@ -2437,21 +2387,9 @@ Value *LLParser::PerFunctionState::GetVal(unsigned ID, Type *Ty, LocTy Loc,
// Otherwise, create a new forward reference for this value and remember it.
Value *FwdVal;
if (Ty->isLabelTy()) {
- assert(!OC);
FwdVal = BasicBlock::Create(F.getContext(), "", &F);
- } else if (!OC) {
- FwdVal = new Argument(Ty);
} else {
- switch (OC) {
- case OC_CatchPad:
- FwdVal = CatchPadInst::Create(&F.getEntryBlock(), &F.getEntryBlock(), {});
- break;
- case OC_CleanupPad:
- FwdVal = CleanupPadInst::Create(F.getContext(), {});
- break;
- default:
- llvm_unreachable("unexpected constraint");
- }
+ FwdVal = new Argument(Ty);
}
ForwardRefValIDs[ID] = std::make_pair(FwdVal, Loc);
@@ -2487,17 +2425,6 @@ bool LLParser::PerFunctionState::SetInstName(int NameID,
if (Sentinel->getType() != Inst->getType())
return P.Error(NameLoc, "instruction forward referenced with type '" +
getTypeString(FI->second.first->getType()) + "'");
- // Check operator constraints. We only put cleanuppads or catchpads in
- // the forward value map if the value is constrained to match.
- if (isa<CatchPadInst>(Sentinel)) {
- if (!isa<CatchPadInst>(Inst))
- return P.Error(FI->second.second,
- "'%" + Twine(NameID) + "' is not a catchpad");
- } else if (isa<CleanupPadInst>(Sentinel)) {
- if (!isa<CleanupPadInst>(Inst))
- return P.Error(FI->second.second,
- "'%" + Twine(NameID) + "' is not a cleanuppad");
- }
Sentinel->replaceAllUsesWith(Inst);
delete Sentinel;
@@ -2515,17 +2442,6 @@ bool LLParser::PerFunctionState::SetInstName(int NameID,
if (Sentinel->getType() != Inst->getType())
return P.Error(NameLoc, "instruction forward referenced with type '" +
getTypeString(FI->second.first->getType()) + "'");
- // Check operator constraints. We only put cleanuppads or catchpads in
- // the forward value map if the value is constrained to match.
- if (isa<CatchPadInst>(Sentinel)) {
- if (!isa<CatchPadInst>(Inst))
- return P.Error(FI->second.second,
- "'%" + NameStr + "' is not a catchpad");
- } else if (isa<CleanupPadInst>(Sentinel)) {
- if (!isa<CleanupPadInst>(Inst))
- return P.Error(FI->second.second,
- "'%" + NameStr + "' is not a cleanuppad");
- }
Sentinel->replaceAllUsesWith(Inst);
delete Sentinel;
@@ -4235,30 +4151,18 @@ bool LLParser::ParseMetadata(Metadata *&MD, PerFunctionState *PFS) {
//===----------------------------------------------------------------------===//
bool LLParser::ConvertValIDToValue(Type *Ty, ValID &ID, Value *&V,
- PerFunctionState *PFS,
- OperatorConstraint OC) {
+ PerFunctionState *PFS) {
if (Ty->isFunctionTy())
return Error(ID.Loc, "functions are not values, refer to them as pointers");
- if (OC && ID.Kind != ValID::t_LocalID && ID.Kind != ValID::t_LocalName) {
- switch (OC) {
- case OC_CatchPad:
- return Error(ID.Loc, "Catchpad value required in this position");
- case OC_CleanupPad:
- return Error(ID.Loc, "Cleanuppad value required in this position");
- default:
- llvm_unreachable("Unexpected constraint kind");
- }
- }
-
switch (ID.Kind) {
case ValID::t_LocalID:
if (!PFS) return Error(ID.Loc, "invalid use of function-local name");
- V = PFS->GetVal(ID.UIntVal, Ty, ID.Loc, OC);
+ V = PFS->GetVal(ID.UIntVal, Ty, ID.Loc);
return V == nullptr;
case ValID::t_LocalName:
if (!PFS) return Error(ID.Loc, "invalid use of function-local name");
- V = PFS->GetVal(ID.StrVal, Ty, ID.Loc, OC);
+ V = PFS->GetVal(ID.StrVal, Ty, ID.Loc);
return V == nullptr;
case ValID::t_InlineAsm: {
if (!ID.FTy || !InlineAsm::Verify(ID.FTy, ID.StrVal2))
@@ -4385,11 +4289,10 @@ bool LLParser::parseConstantValue(Type *Ty, Constant *&C) {
}
}
-bool LLParser::ParseValue(Type *Ty, Value *&V, PerFunctionState *PFS,
- OperatorConstraint OC) {
+bool LLParser::ParseValue(Type *Ty, Value *&V, PerFunctionState *PFS) {
V = nullptr;
ValID ID;
- return ParseValID(ID, PFS) || ConvertValIDToValue(Ty, ID, V, PFS, OC);
+ return ParseValID(ID, PFS) || ConvertValIDToValue(Ty, ID, V, PFS);
}
bool LLParser::ParseTypeAndValue(Value *&V, PerFunctionState *PFS) {
@@ -4818,11 +4721,10 @@ int LLParser::ParseInstruction(Instruction *&Inst, BasicBlock *BB,
case lltok::kw_resume: return ParseResume(Inst, PFS);
case lltok::kw_cleanupret: return ParseCleanupRet(Inst, PFS);
case lltok::kw_catchret: return ParseCatchRet(Inst, PFS);
- case lltok::kw_catchpad: return ParseCatchPad(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);
+ case lltok::kw_catchswitch: return ParseCatchSwitch(Inst, PFS);
+ case lltok::kw_catchpad: return ParseCatchPad(Inst, PFS);
+ case lltok::kw_terminatepad:return ParseTerminatePad(Inst, PFS);
+ case lltok::kw_cleanuppad: return ParseCleanupPad(Inst, PFS);
// Binary Operators.
case lltok::kw_add:
case lltok::kw_sub:
@@ -5262,11 +5164,14 @@ bool LLParser::ParseExceptionArgs(SmallVectorImpl<Value *> &Args,
}
/// ParseCleanupRet
-/// ::= 'cleanupret' Value unwind ('to' 'caller' | TypeAndValue)
+/// ::= 'cleanupret' from Value unwind ('to' 'caller' | TypeAndValue)
bool LLParser::ParseCleanupRet(Instruction *&Inst, PerFunctionState &PFS) {
Value *CleanupPad = nullptr;
- if (ParseValue(Type::getTokenTy(Context), CleanupPad, PFS, OC_CleanupPad))
+ if (ParseToken(lltok::kw_from, "expected 'from' after cleanupret"))
+ return true;
+
+ if (ParseValue(Type::getTokenTy(Context), CleanupPad, PFS))
return true;
if (ParseToken(lltok::kw_unwind, "expected 'unwind' in cleanupret"))
@@ -5283,16 +5188,19 @@ bool LLParser::ParseCleanupRet(Instruction *&Inst, PerFunctionState &PFS) {
}
}
- Inst = CleanupReturnInst::Create(cast<CleanupPadInst>(CleanupPad), UnwindBB);
+ Inst = CleanupReturnInst::Create(CleanupPad, UnwindBB);
return false;
}
/// ParseCatchRet
-/// ::= 'catchret' Value 'to' TypeAndValue
+/// ::= 'catchret' from Parent Value 'to' TypeAndValue
bool LLParser::ParseCatchRet(Instruction *&Inst, PerFunctionState &PFS) {
Value *CatchPad = nullptr;
- if (ParseValue(Type::getTokenTy(Context), CatchPad, PFS, OC_CatchPad))
+ if (ParseToken(lltok::kw_from, "expected 'from' after catchret"))
+ return true;
+
+ if (ParseValue(Type::getTokenTy(Context), CatchPad, PFS))
return true;
BasicBlock *BB;
@@ -5300,114 +5208,140 @@ bool LLParser::ParseCatchRet(Instruction *&Inst, PerFunctionState &PFS) {
ParseTypeAndBasicBlock(BB, PFS))
return true;
- Inst = CatchReturnInst::Create(cast<CatchPadInst>(CatchPad), BB);
+ Inst = CatchReturnInst::Create(CatchPad, BB);
return false;
}
-/// ParseCatchPad
-/// ::= 'catchpad' ParamList 'to' TypeAndValue 'unwind' TypeAndValue
-bool LLParser::ParseCatchPad(Instruction *&Inst, PerFunctionState &PFS) {
- SmallVector<Value *, 8> Args;
- if (ParseExceptionArgs(Args, PFS))
+/// ParseCatchSwitch
+/// ::= 'catchswitch' within Parent
+bool LLParser::ParseCatchSwitch(Instruction *&Inst, PerFunctionState &PFS) {
+ Value *ParentPad;
+ LocTy BBLoc;
+
+ if (ParseToken(lltok::kw_within, "expected 'within' after catchswitch"))
return true;
- BasicBlock *NormalBB, *UnwindBB;
- if (ParseToken(lltok::kw_to, "expected 'to' in catchpad") ||
- ParseTypeAndBasicBlock(NormalBB, PFS) ||
- ParseToken(lltok::kw_unwind, "expected 'unwind' in catchpad") ||
- ParseTypeAndBasicBlock(UnwindBB, PFS))
+ if (Lex.getKind() != lltok::kw_none && Lex.getKind() != lltok::LocalVar &&
+ Lex.getKind() != lltok::LocalVarID)
+ return TokError("expected scope value for catchswitch");
+
+ if (ParseValue(Type::getTokenTy(Context), ParentPad, PFS))
return true;
- Inst = CatchPadInst::Create(NormalBB, UnwindBB, Args);
- return false;
-}
+ if (ParseToken(lltok::lsquare, "expected '[' with catchswitch labels"))
+ return true;
-/// ParseTerminatePad
-/// ::= 'terminatepad' ParamList 'to' TypeAndValue
-bool LLParser::ParseTerminatePad(Instruction *&Inst, PerFunctionState &PFS) {
- SmallVector<Value *, 8> Args;
- if (ParseExceptionArgs(Args, PFS))
+ SmallVector<BasicBlock *, 32> Table;
+ do {
+ BasicBlock *DestBB;
+ if (ParseTypeAndBasicBlock(DestBB, PFS))
+ return true;
+ Table.push_back(DestBB);
+ } while (EatIfPresent(lltok::comma));
+
+ if (ParseToken(lltok::rsquare, "expected ']' after catchswitch labels"))
return true;
- if (ParseToken(lltok::kw_unwind, "expected 'unwind' in terminatepad"))
+ if (ParseToken(lltok::kw_unwind,
+ "expected 'unwind' after catchswitch scope"))
return true;
BasicBlock *UnwindBB = nullptr;
- if (Lex.getKind() == lltok::kw_to) {
- Lex.Lex();
- if (ParseToken(lltok::kw_caller, "expected 'caller' in terminatepad"))
+ if (EatIfPresent(lltok::kw_to)) {
+ if (ParseToken(lltok::kw_caller, "expected 'caller' in catchswitch"))
return true;
} else {
- if (ParseTypeAndBasicBlock(UnwindBB, PFS)) {
+ if (ParseTypeAndBasicBlock(UnwindBB, PFS))
return true;
- }
}
- Inst = TerminatePadInst::Create(Context, UnwindBB, Args);
+ auto *CatchSwitch =
+ CatchSwitchInst::Create(ParentPad, UnwindBB, Table.size());
+ for (BasicBlock *DestBB : Table)
+ CatchSwitch->addHandler(DestBB);
+ Inst = CatchSwitch;
return false;
}
-/// ParseCleanupPad
-/// ::= 'cleanuppad' ParamList
-bool LLParser::ParseCleanupPad(Instruction *&Inst, PerFunctionState &PFS) {
+/// ParseCatchPad
+/// ::= 'catchpad' ParamList 'to' TypeAndValue 'unwind' TypeAndValue
+bool LLParser::ParseCatchPad(Instruction *&Inst, PerFunctionState &PFS) {
+ Value *CatchSwitch = nullptr;
+
+ if (ParseToken(lltok::kw_within, "expected 'within' after catchpad"))
+ return true;
+
+ if (Lex.getKind() != lltok::LocalVar && Lex.getKind() != lltok::LocalVarID)
+ return TokError("expected scope value for catchpad");
+
+ if (ParseValue(Type::getTokenTy(Context), CatchSwitch, PFS))
+ return true;
+
SmallVector<Value *, 8> Args;
if (ParseExceptionArgs(Args, PFS))
return true;
- Inst = CleanupPadInst::Create(Context, Args);
+ Inst = CatchPadInst::Create(CatchSwitch, Args);
return false;
}
-/// ParseCatchEndPad
-/// ::= 'catchendpad' unwind ('to' 'caller' | TypeAndValue)
-bool LLParser::ParseCatchEndPad(Instruction *&Inst, PerFunctionState &PFS) {
- if (ParseToken(lltok::kw_unwind, "expected 'unwind' in catchendpad"))
+/// ParseTerminatePad
+/// ::= 'terminatepad' within Parent ParamList 'to' TypeAndValue
+bool LLParser::ParseTerminatePad(Instruction *&Inst, PerFunctionState &PFS) {
+ Value *ParentPad = nullptr;
+
+ if (ParseToken(lltok::kw_within, "expected 'within' after terminatepad"))
+ return true;
+
+ if (Lex.getKind() != lltok::kw_none && Lex.getKind() != lltok::LocalVar &&
+ Lex.getKind() != lltok::LocalVarID)
+ return TokError("expected scope value for terminatepad");
+
+ if (ParseValue(Type::getTokenTy(Context), ParentPad, PFS))
+ return true;
+
+ SmallVector<Value *, 8> Args;
+ if (ParseExceptionArgs(Args, PFS))
+ return true;
+
+ if (ParseToken(lltok::kw_unwind, "expected 'unwind' in terminatepad"))
return true;
BasicBlock *UnwindBB = nullptr;
if (Lex.getKind() == lltok::kw_to) {
Lex.Lex();
- if (Lex.getKind() == lltok::kw_caller) {
- Lex.Lex();
- } else {
+ if (ParseToken(lltok::kw_caller, "expected 'caller' in terminatepad"))
return true;
- }
} else {
if (ParseTypeAndBasicBlock(UnwindBB, PFS)) {
return true;
}
}
- Inst = CatchEndPadInst::Create(Context, UnwindBB);
+ Inst = TerminatePadInst::Create(ParentPad, UnwindBB, Args);
return false;
}
-/// ParseCatchEndPad
-/// ::= 'cleanupendpad' Value unwind ('to' 'caller' | TypeAndValue)
-bool LLParser::ParseCleanupEndPad(Instruction *&Inst, PerFunctionState &PFS) {
- Value *CleanupPad = nullptr;
+/// ParseCleanupPad
+/// ::= 'cleanuppad' within Parent ParamList
+bool LLParser::ParseCleanupPad(Instruction *&Inst, PerFunctionState &PFS) {
+ Value *ParentPad = nullptr;
- if (ParseValue(Type::getTokenTy(Context), CleanupPad, PFS, OC_CleanupPad))
+ if (ParseToken(lltok::kw_within, "expected 'within' after cleanuppad"))
return true;
- if (ParseToken(lltok::kw_unwind, "expected 'unwind' in catchendpad"))
+ if (Lex.getKind() != lltok::kw_none && Lex.getKind() != lltok::LocalVar &&
+ Lex.getKind() != lltok::LocalVarID)
+ return TokError("expected scope value for cleanuppad");
+
+ if (ParseValue(Type::getTokenTy(Context), ParentPad, PFS))
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;
- }
- }
+ SmallVector<Value *, 8> Args;
+ if (ParseExceptionArgs(Args, PFS))
+ return true;
- Inst = CleanupEndPadInst::Create(cast<CleanupPadInst>(CleanupPad), UnwindBB);
+ Inst = CleanupPadInst::Create(ParentPad, Args);
return false;
}
diff --git a/lib/AsmParser/LLParser.h b/lib/AsmParser/LLParser.h
index d4384db9bf0..97a13f1a057 100644
--- a/lib/AsmParser/LLParser.h
+++ b/lib/AsmParser/LLParser.h
@@ -108,14 +108,6 @@ namespace llvm {
unsigned MDKind, MDSlot;
};
- /// Indicates which operator an operand allows (for the few operands that
- /// may only reference a certain operator).
- enum OperatorConstraint {
- OC_None = 0, // No constraint
- OC_CatchPad, // Must be CatchPadInst
- OC_CleanupPad // Must be CleanupPadInst
- };
-
SmallVector<Instruction*, 64> InstsWithTBAATag;
// Type resolution handling data structures. The location is set when we
@@ -337,10 +329,8 @@ namespace llvm {
/// GetVal - Get a value with the specified name or ID, creating a
/// forward reference record if needed. This can return null if the value
/// exists but does not have the right type.
- Value *GetVal(const std::string &Name, Type *Ty, LocTy Loc,
- OperatorConstraint OC = OC_None);
- Value *GetVal(unsigned ID, Type *Ty, LocTy Loc,
- OperatorConstraint OC = OC_None);
+ Value *GetVal(const std::string &Name, Type *Ty, LocTy Loc);
+ Value *GetVal(unsigned ID, Type *Ty, LocTy Loc);
/// SetInstName - After an instruction is parsed and inserted into its
/// basic block, this installs its name.
@@ -362,16 +352,14 @@ namespace llvm {
};
bool ConvertValIDToValue(Type *Ty, ValID &ID, Value *&V,
- PerFunctionState *PFS,
- OperatorConstraint OC = OC_None);
+ PerFunctionState *PFS);
bool parseConstantValue(Type *Ty, Constant *&C);
- bool ParseValue(Type *Ty, Value *&V, PerFunctionState *PFS,
- OperatorConstraint OC = OC_None);
- bool ParseValue(Type *Ty, Value *&V, PerFunctionState &PFS,
- OperatorConstraint OC = OC_None) {
- return ParseValue(Ty, V, &PFS, OC);
+ bool ParseValue(Type *Ty, Value *&V, PerFunctionState *PFS);
+ bool ParseValue(Type *Ty, Value *&V, PerFunctionState &PFS) {
+ return ParseValue(Ty, V, &PFS);
}
+
bool ParseValue(Type *Ty, Value *&V, LocTy &Loc,
PerFunctionState &PFS) {
Loc = Lex.getLoc();
@@ -475,11 +463,10 @@ namespace llvm {
bool ParseResume(Instruction *&Inst, PerFunctionState &PFS);
bool ParseCleanupRet(Instruction *&Inst, PerFunctionState &PFS);
bool ParseCatchRet(Instruction *&Inst, PerFunctionState &PFS);
+ bool ParseCatchSwitch(Instruction *&Inst, PerFunctionState &PFS);
bool ParseCatchPad(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);
diff --git a/lib/AsmParser/LLToken.h b/lib/AsmParser/LLToken.h
index 10c840d257f..b35aae5f570 100644
--- a/lib/AsmParser/LLToken.h
+++ b/lib/AsmParser/LLToken.h
@@ -52,6 +52,8 @@ namespace lltok {
kw_undef, kw_null, kw_none,
kw_to,
kw_caller,
+ kw_within,
+ kw_from,
kw_tail,
kw_musttail,
kw_notail,
@@ -182,8 +184,8 @@ namespace lltok {
kw_landingpad, kw_personality, kw_cleanup, kw_catch, kw_filter,
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_cleanupendpad,
+ kw_unreachable, kw_cleanupret, kw_catchswitch, kw_catchret, kw_catchpad,
+ kw_terminatepad, kw_cleanuppad,
kw_alloca, kw_load, kw_store, kw_fence, kw_cmpxchg, kw_atomicrmw,
kw_getelementptr,
diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp
index 4b5af3dd80f..e85cf4d8ebd 100644
--- a/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -42,14 +42,6 @@ enum {
SWITCH_INST_MAGIC = 0x4B5 // May 2012 => 1205 => Hex
};
-/// Indicates which operator an operand allows (for the few operands that may
-/// only reference a certain operator).
-enum OperatorConstraint {
- OC_None = 0, // No constraint
- OC_CatchPad, // Must be CatchPadInst
- OC_CleanupPad // Must be CleanupPadInst
-};
-
class BitcodeReaderValueList {
std::vector<WeakVH> ValuePtrs;
@@ -93,10 +85,9 @@ public:
}
Constant *getConstantFwdRef(unsigned Idx, Type *Ty);
- Value *getValueFwdRef(unsigned Idx, Type *Ty,
- OperatorConstraint OC = OC_None);
+ Value *getValueFwdRef(unsigned Idx, Type *Ty);
- bool assignValue(Value *V, unsigned Idx);
+ void assignValue(Value *V, unsigned Idx);
/// Once all constants are read, this method bulk resolves any forward
/// references.
@@ -297,11 +288,10 @@ private:
StructType *createIdentifiedStructType(LLVMContext &Context);
Type *getTypeByID(unsigned ID);
- Value *getFnValueByID(unsigned ID, Type *Ty,
- OperatorConstraint OC = OC_None) {
+ Value *getFnValueByID(unsigned ID, Type *Ty) {
if (Ty && Ty->isMetadataTy())
return MetadataAsValue::get(Ty->getContext(), getFnMetadataByID(ID));
- return ValueList.getValueFwdRef(ID, Ty, OC);
+ return ValueList.getValueFwdRef(ID, Ty);
}
Metadata *getFnMetadataByID(unsigned ID) {
return MDValueList.getValueFwdRef(ID);
@@ -344,9 +334,8 @@ private:
/// past the number of slots used by the value in the record. Return true if
/// there is an error.
bool popValue(SmallVectorImpl<uint64_t> &Record, unsigned &Slot,
- unsigned InstNum, Type *Ty, Value *&ResVal,
- OperatorConstraint OC = OC_None) {
- if (getValue(Record, Slot, InstNum, Ty, ResVal, OC))
+ unsigned InstNum, Type *Ty, Value *&ResVal) {
+ if (getValue(Record, Slot, InstNum, Ty, ResVal))
return true;
// All values currently take a single record slot.
++Slot;
@@ -355,34 +344,32 @@ private:
/// Like popValue, but does not increment the Slot number.
bool getValue(SmallVectorImpl<uint64_t> &Record, unsigned Slot,
- unsigned InstNum, Type *Ty, Value *&ResVal,
- OperatorConstraint OC = OC_None) {
- ResVal = getValue(Record, Slot, InstNum, Ty, OC);
+ unsigned InstNum, Type *Ty, Value *&ResVal) {
+ ResVal = getValue(Record, Slot, InstNum, Ty);
return ResVal == nullptr;
}
/// Version of getValue that returns ResVal directly, or 0 if there is an
/// error.
Value *getValue(SmallVectorImpl<uint64_t> &Record, unsigned Slot,
- unsigned InstNum, Type *Ty, OperatorConstraint OC = OC_None) {
+ unsigned InstNum, Type *Ty) {
if (Slot == Record.size()) return nullptr;
unsigned ValNo = (unsigned)Record[Slot];
// Adjust the ValNo, if it was encoded relative to the InstNum.
if (UseRelativeIDs)
ValNo = InstNum - ValNo;
- return getFnValueByID(ValNo, Ty, OC);
+ return getFnValueByID(ValNo, Ty);
}
/// Like getValue, but decodes signed VBRs.
Value *getValueSigned(SmallVectorImpl<uint64_t> &Record, unsigned Slot,
- unsigned InstNum, Type *Ty,
- OperatorConstraint OC = OC_None) {
+ unsigned InstNum, Type *Ty) {
if (Slot == Record.size()) return nullptr;
unsigned ValNo = (unsigned)decodeSignRotatedValue(Record[Slot]);
// Adjust the ValNo, if it was encoded relative to the InstNum.
if (UseRelativeIDs)
ValNo = InstNum - ValNo;
- return getFnValueByID(ValNo, Ty, OC);
+ return getFnValueByID(ValNo, Ty);
}
/// Converts alignment exponent (i.e. power of two (or zero)) to the
@@ -898,10 +885,10 @@ struct OperandTraits<ConstantPlaceHolder> :
DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantPlaceHolder, Value)
}
-bool BitcodeReaderValueList::assignValue(Value *V, unsigned Idx) {
+void BitcodeReaderValueList::assignValue(Value *V, unsigned Idx) {
if (Idx == size()) {
push_back(V);
- return false;
+ return;
}
if (Idx >= size())
@@ -910,7 +897,7 @@ bool BitcodeReaderValueList::assignValue(Value *V, unsigned Idx) {
WeakVH &OldV = ValuePtrs[Idx];
if (!OldV) {
OldV = V;
- return false;
+ return;
}
// Handle constants and non-constants (e.g. instrs) differently for
@@ -921,26 +908,11 @@ bool BitcodeReaderValueList::assignValue(Value *V, unsigned Idx) {
} else {
// If there was a forward reference to this value, replace it.
Value *PrevVal = OldV;
- // Check operator constraints. We only put cleanuppads or catchpads in
- // the forward value map if the value is constrained to match.
- if (CatchPadInst *CatchPad = dyn_cast<CatchPadInst>(PrevVal)) {
- if (!isa<CatchPadInst>(V))
- return true;
- // Delete the dummy basic block that was created with the sentinel
- // catchpad.
- BasicBlock *DummyBlock = CatchPad->getUnwindDest();
- assert(DummyBlock == CatchPad->getNormalDest());
- CatchPad->dropAllReferences();
- delete DummyBlock;
- } else if (isa<CleanupPadInst>(PrevVal)) {
- if (!isa<CleanupPadInst>(V))
- return true;
- }
OldV->replaceAllUsesWith(V);
delete PrevVal;
}
- return false;
+ return;
}
@@ -961,8 +933,7 @@ Constant *BitcodeReaderValueList::getConstantFwdRef(unsigned Idx,
return C;
}
-Value *BitcodeReaderValueList::getValueFwdRef(unsigned Idx, Type *Ty,
- OperatorConstraint OC) {
+Value *BitcodeReaderValueList::getValueFwdRef(unsigned Idx, Type *Ty) {
// Bail out for a clearly invalid value. This would make us call resize(0)
if (Idx == UINT_MAX)
return nullptr;
@@ -974,39 +945,14 @@ Value *BitcodeReaderValueList::getValueFwdRef(unsigned Idx, Type *Ty,
// If the types don't match, it's invalid.
if (Ty && Ty != V->getType())
return nullptr;
- if (!OC)
- return V;
- // Use dyn_cast to enforce operator constraints
- switch (OC) {
- case OC_CatchPad:
- return dyn_cast<CatchPadInst>(V);
- case OC_CleanupPad:
- return dyn_cast<CleanupPadInst>(V);
- default:
- llvm_unreachable("Unexpected operator constraint");
- }
+ return V;
}
// No type specified, must be invalid reference.
if (!Ty) return nullptr;
// Create and return a placeholder, which will later be RAUW'd.
- Value *V;
- switch (OC) {
- case OC_None:
- V = new Argument(Ty);
- break;
- case OC_CatchPad: {
- BasicBlock *BB = BasicBlock::Create(Context);
- V = CatchPadInst::Create(BB, BB, {});
- break;
- }
- default:
- assert(OC == OC_CleanupPad && "unexpected operator constraint");
- V = CleanupPadInst::Create(Context, {});
- break;
- }
-
+ Value *V = new Argument(Ty);
ValuePtrs[Idx] = V;
return V;
}
@@ -3023,8 +2969,7 @@ std::error_code BitcodeReader::parseConstants() {
}
}
- if (ValueList.assignValue(V, NextCstNo))
- return error("Invalid forward reference");
+ ValueList.assignValue(V, NextCstNo);
++NextCstNo;
}
}
@@ -4470,8 +4415,8 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) {
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);
+ Value *CleanupPad =
+ getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context));
if (!CleanupPad)
return error("Invalid record");
BasicBlock *UnwindDest = nullptr;
@@ -4481,8 +4426,7 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) {
return error("Invalid record");
}
- I = CleanupReturnInst::Create(cast<CleanupPadInst>(CleanupPad),
- UnwindDest);
+ I = CleanupReturnInst::Create(CleanupPad, UnwindDest);
InstructionList.push_back(I);
break;
}
@@ -4490,57 +4434,68 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) {
if (Record.size() != 2)
return error("Invalid record");
unsigned Idx = 0;
- Value *CatchPad = getValue(Record, Idx++, NextValueNo,
- Type::getTokenTy(Context), OC_CatchPad);
+ Value *CatchPad =
+ getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context));
if (!CatchPad)
return error("Invalid record");
BasicBlock *BB = getBasicBlock(Record[Idx++]);
if (!BB)
return error("Invalid record");
- I = CatchReturnInst::Create(cast<CatchPadInst>(CatchPad), BB);
+ I = CatchReturnInst::Create(CatchPad, BB);
InstructionList.push_back(I);
break;
}
- case bitc::FUNC_CODE_INST_CATCHPAD: { // CATCHPAD: [bb#,bb#,num,(ty,val)*]
- if (Record.size() < 3)
+ case bitc::FUNC_CODE_INST_CATCHSWITCH: { // CATCHSWITCH: [tok,num,(bb)*,bb?]
+ // We must have, at minimum, the outer scope and the number of arguments.
+ if (Record.size() < 2)
return error("Invalid record");
+
unsigned Idx = 0;
- BasicBlock *NormalBB = getBasicBlock(Record[Idx++]);
- if (!NormalBB)
- return error("Invalid record");
- BasicBlock *UnwindBB = getBasicBlock(Record[Idx++]);
- if (!UnwindBB)
- return error("Invalid record");
- unsigned NumArgOperands = Record[Idx++];
- SmallVector<Value *, 2> Args;
- for (unsigned Op = 0; Op != NumArgOperands; ++Op) {
- Value *Val;
- if (getValueTypePair(Record, Idx, NextValueNo, Val))
+
+ Value *ParentPad =
+ getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context));
+
+ unsigned NumHandlers = Record[Idx++];
+
+ SmallVector<BasicBlock *, 2> Handlers;
+ for (unsigned Op = 0; Op != NumHandlers; ++Op) {
+ BasicBlock *BB = getBasicBlock(Record[Idx++]);
+ if (!BB)
+ return error("Invalid record");
+ Handlers.push_back(BB);
+ }
+
+ BasicBlock *UnwindDest = nullptr;
+ if (Idx + 1 == Record.size()) {
+ UnwindDest = getBasicBlock(Record[Idx++]);
+ if (!UnwindDest)
return error("Invalid record");
- Args.push_back(Val);
}
+
if (Record.size() != Idx)
return error("Invalid record");
- I = CatchPadInst::Create(NormalBB, UnwindBB, Args);
+ auto *CatchSwitch =
+ CatchSwitchInst::Create(ParentPad, UnwindDest, NumHandlers);
+ for (BasicBlock *Handler : Handlers)
+ CatchSwitch->addHandler(Handler);
+ I = CatchSwitch;
InstructionList.push_back(I);
break;
}
- case bitc::FUNC_CODE_INST_TERMINATEPAD: { // TERMINATEPAD: [bb#,num,(ty,val)*]
- if (Record.size() < 1)
+ case bitc::FUNC_CODE_INST_TERMINATEPAD: { // TERMINATEPAD: [tok,bb#,num,(ty,val)*]
+ // We must have, at minimum, the outer scope and the number of arguments.
+ if (Record.size() < 2)
return error("Invalid record");
+
unsigned Idx = 0;
- bool HasUnwindDest = !!Record[Idx++];
- BasicBlock *UnwindDest = nullptr;
- if (HasUnwindDest) {
- if (Idx == Record.size())
- return error("Invalid record");
- UnwindDest = getBasicBlock(Record[Idx++]);
- if (!UnwindDest)
- return error("Invalid record");
- }
+
+ Value *ParentPad =
+ getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context));
+
unsigned NumArgOperands = Record[Idx++];
+
SmallVector<Value *, 2> Args;
for (unsigned Op = 0; Op != NumArgOperands; ++Op) {
Value *Val;
@@ -4548,18 +4503,34 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) {
return error("Invalid record");
Args.push_back(Val);
}
+
+ BasicBlock *UnwindDest = nullptr;
+ if (Idx + 1 == Record.size()) {
+ UnwindDest = getBasicBlock(Record[Idx++]);
+ if (!UnwindDest)
+ return error("Invalid record");
+ }
+
if (Record.size() != Idx)
return error("Invalid record");
- I = TerminatePadInst::Create(Context, UnwindDest, Args);
+ I = TerminatePadInst::Create(ParentPad, UnwindDest, Args);
InstructionList.push_back(I);
break;
}
- case bitc::FUNC_CODE_INST_CLEANUPPAD: { // CLEANUPPAD: [num,(ty,val)*]
- if (Record.size() < 1)
+ case bitc::FUNC_CODE_INST_CATCHPAD:
+ case bitc::FUNC_CODE_INST_CLEANUPPAD: { // [tok,num,(ty,val)*]
+ // We must have, at minimum, the outer scope and the number of arguments.
+ if (Record.size() < 2)
return error("Invalid record");
+
unsigned Idx = 0;
+
+ Value *ParentPad =
+ getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context));
+
unsigned NumArgOperands = Record[Idx++];
+
SmallVector<Value *, 2> Args;
for (unsigned Op = 0; Op != NumArgOperands; ++Op) {
Value *Val;
@@ -4567,42 +4538,14 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) {
return error("Invalid record");
Args.push_back(Val);
}
- if (Record.size() != Idx)
- return error("Invalid record");
- I = CleanupPadInst::Create(Context, Args);
- InstructionList.push_back(I);
- break;
- }
- case bitc::FUNC_CODE_INST_CATCHENDPAD: { // CATCHENDPADINST: [bb#] or []
- if (Record.size() > 1)
- return error("Invalid record");
- BasicBlock *BB = nullptr;
- if (Record.size() == 1) {
- BB = getBasicBlock(Record[0]);
- if (!BB)
- return error("Invalid record");
- }
- I = CatchEndPadInst::Create(Context, BB);
- 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)
+ if (Record.size() != Idx)
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);
+ if (BitCode == bitc::FUNC_CODE_INST_CLEANUPPAD)
+ I = CleanupPadInst::Create(ParentPad, Args);
+ else
+ I = CatchPadInst::Create(ParentPad, Args);
InstructionList.push_back(I);
break;
}
@@ -5224,8 +5167,7 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) {
// Non-void values get registered in the value table for future use.
if (I && !I->getType()->isVoidTy())
- if (ValueList.assignValue(I, NextValueNo++))
- return error("Invalid forward reference");
+ ValueList.assignValue(I, NextValueNo++);
}
OutOfRecordLoop:
diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp
index 201b4bc34c2..bc6f0edafac 100644
--- a/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -1997,51 +1997,47 @@ static void WriteInstruction(const Instruction &I, unsigned InstID,
Vals.push_back(VE.getValueID(CRI.getSuccessor()));
break;
}
+ case Instruction::CleanupPad:
case Instruction::CatchPad: {
- Code = bitc::FUNC_CODE_INST_CATCHPAD;
- const auto &CPI = cast<CatchPadInst>(I);
- Vals.push_back(VE.getValueID(CPI.getNormalDest()));
- Vals.push_back(VE.getValueID(CPI.getUnwindDest()));
- unsigned NumArgOperands = CPI.getNumArgOperands();
+ const auto &FuncletPad = cast<FuncletPadInst>(I);
+ Code = isa<CatchPadInst>(FuncletPad) ? bitc::FUNC_CODE_INST_CATCHPAD
+ : bitc::FUNC_CODE_INST_CLEANUPPAD;
+ pushValue(FuncletPad.getParentPad(), InstID, Vals, VE);
+
+ unsigned NumArgOperands = FuncletPad.getNumArgOperands();
Vals.push_back(NumArgOperands);
for (unsigned Op = 0; Op != NumArgOperands; ++Op)
- PushValueAndType(CPI.getArgOperand(Op), InstID, Vals, VE);
+ PushValueAndType(FuncletPad.getArgOperand(Op), InstID, Vals, VE);
+ break;
+ }
+ case Instruction::CatchSwitch: {
+ Code = bitc::FUNC_CODE_INST_CATCHSWITCH;
+ const auto &CatchSwitch = cast<CatchSwitchInst>(I);
+
+ pushValue(CatchSwitch.getParentPad(), InstID, Vals, VE);
+
+ unsigned NumHandlers = CatchSwitch.getNumHandlers();
+ Vals.push_back(NumHandlers);
+ for (const BasicBlock *CatchPadBB : CatchSwitch.handlers())
+ Vals.push_back(VE.getValueID(CatchPadBB));
+
+ if (CatchSwitch.hasUnwindDest())
+ Vals.push_back(VE.getValueID(CatchSwitch.getUnwindDest()));
break;
}
case Instruction::TerminatePad: {
Code = bitc::FUNC_CODE_INST_TERMINATEPAD;
const auto &TPI = cast<TerminatePadInst>(I);
- Vals.push_back(TPI.hasUnwindDest());
- if (TPI.hasUnwindDest())
- Vals.push_back(VE.getValueID(TPI.getUnwindDest()));
+
+ pushValue(TPI.getParentPad(), InstID, Vals, VE);
+
unsigned NumArgOperands = TPI.getNumArgOperands();
Vals.push_back(NumArgOperands);
for (unsigned Op = 0; Op != NumArgOperands; ++Op)
PushValueAndType(TPI.getArgOperand(Op), InstID, Vals, VE);
- break;
- }
- case Instruction::CleanupPad: {
- Code = bitc::FUNC_CODE_INST_CLEANUPPAD;
- const auto &CPI = cast<CleanupPadInst>(I);
- unsigned NumOperands = CPI.getNumOperands();
- Vals.push_back(NumOperands);
- for (unsigned Op = 0; Op != NumOperands; ++Op)
- PushValueAndType(CPI.getOperand(Op), InstID, Vals, VE);
- break;
- }
- case Instruction::CatchEndPad: {
- Code = bitc::FUNC_CODE_INST_CATCHENDPAD;
- const auto &CEPI = cast<CatchEndPadInst>(I);
- if (CEPI.hasUnwindDest())
- 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()));
+
+ if (TPI.hasUnwindDest())
+ Vals.push_back(VE.getValueID(TPI.getUnwindDest()));
break;
}
case Instruction::Unreachable:
diff --git a/lib/CodeGen/AsmPrinter/WinException.cpp b/lib/CodeGen/AsmPrinter/WinException.cpp
index cd1f3f51bc4..e2994172415 100644
--- a/lib/CodeGen/AsmPrinter/WinException.cpp
+++ b/lib/CodeGen/AsmPrinter/WinException.cpp
@@ -344,42 +344,32 @@ class InvokeStateChangeIterator {
InvokeStateChangeIterator(const WinEHFuncInfo &EHInfo,
MachineFunction::const_iterator MFI,
MachineFunction::const_iterator MFE,
- MachineBasicBlock::const_iterator MBBI)
- : EHInfo(EHInfo), MFI(MFI), MFE(MFE), MBBI(MBBI) {
+ MachineBasicBlock::const_iterator MBBI,
+ int BaseState)
+ : EHInfo(EHInfo), MFI(MFI), MFE(MFE), MBBI(MBBI), BaseState(BaseState) {
LastStateChange.PreviousEndLabel = nullptr;
LastStateChange.NewStartLabel = nullptr;
- LastStateChange.NewState = NullState;
+ LastStateChange.NewState = BaseState;
scan();
}
public:
static iterator_range<InvokeStateChangeIterator>
- range(const WinEHFuncInfo &EHInfo, const MachineFunction &MF) {
- // Reject empty MFs to simplify bookkeeping by ensuring that we can get the
- // end of the last block.
- assert(!MF.empty());
- auto FuncBegin = MF.begin();
- auto FuncEnd = MF.end();
- auto BlockBegin = FuncBegin->begin();
- auto BlockEnd = MF.back().end();
- return make_range(
- InvokeStateChangeIterator(EHInfo, FuncBegin, FuncEnd, BlockBegin),
- InvokeStateChangeIterator(EHInfo, FuncEnd, FuncEnd, BlockEnd));
- }
- static iterator_range<InvokeStateChangeIterator>
range(const WinEHFuncInfo &EHInfo, MachineFunction::const_iterator Begin,
- MachineFunction::const_iterator End) {
+ MachineFunction::const_iterator End, int BaseState = NullState) {
// Reject empty ranges to simplify bookkeeping by ensuring that we can get
// the end of the last block.
assert(Begin != End);
auto BlockBegin = Begin->begin();
auto BlockEnd = std::prev(End)->end();
- return make_range(InvokeStateChangeIterator(EHInfo, Begin, End, BlockBegin),
- InvokeStateChangeIterator(EHInfo, End, End, BlockEnd));
+ return make_range(
+ InvokeStateChangeIterator(EHInfo, Begin, End, BlockBegin, BaseState),
+ InvokeStateChangeIterator(EHInfo, End, End, BlockEnd, BaseState));
}
// Iterator methods.
bool operator==(const InvokeStateChangeIterator &O) const {
+ assert(BaseState == O.BaseState);
// Must be visiting same block.
if (MFI != O.MFI)
return false;
@@ -410,6 +400,7 @@ private:
MachineBasicBlock::const_iterator MBBI;
InvokeStateChange LastStateChange;
bool VisitingInvoke = false;
+ int BaseState;
};
} // end anonymous namespace
@@ -421,14 +412,14 @@ InvokeStateChangeIterator &InvokeStateChangeIterator::scan() {
MBBI = MFI->begin();
for (auto MBBE = MFI->end(); MBBI != MBBE; ++MBBI) {
const MachineInstr &MI = *MBBI;
- if (!VisitingInvoke && LastStateChange.NewState != NullState &&
+ if (!VisitingInvoke && LastStateChange.NewState != BaseState &&
MI.isCall() && !EHStreamer::callToNoUnwindFunction(&MI)) {
// Indicate a change of state to the null state. We don't have
// start/end EH labels handy but the caller won't expect them for
// null state regions.
LastStateChange.PreviousEndLabel = CurrentEndLabel;
LastStateChange.NewStartLabel = nullptr;
- LastStateChange.NewState = NullState;
+ LastStateChange.NewState = BaseState;
CurrentEndLabel = nullptr;
// Don't re-visit this instr on the next scan
++MBBI;
@@ -443,18 +434,12 @@ InvokeStateChangeIterator &InvokeStateChangeIterator::scan() {
VisitingInvoke = false;
continue;
}
- auto InvokeMapIter = EHInfo.InvokeToStateMap.find(Label);
+ auto InvokeMapIter = EHInfo.LabelToStateMap.find(Label);
// Ignore EH labels that aren't the ones inserted before an invoke
- if (InvokeMapIter == EHInfo.InvokeToStateMap.end())
+ if (InvokeMapIter == EHInfo.LabelToStateMap.end())
continue;
auto &StateAndEnd = InvokeMapIter->second;
int NewState = StateAndEnd.first;
- // Ignore EH labels explicitly annotated with the null state (which
- // can happen for invokes that unwind to a chain of endpads the last
- // of which unwinds to caller). We'll see the subsequent invoke and
- // report a transition to the null state same as we do for calls.
- if (NewState == NullState)
- continue;
// Keep track of the fact that we're between EH start/end labels so
// we know not to treat the inoke we'll see as unwinding to caller.
VisitingInvoke = true;
@@ -476,11 +461,11 @@ InvokeStateChangeIterator &InvokeStateChangeIterator::scan() {
}
}
// Iteration hit the end of the block range.
- if (LastStateChange.NewState != NullState) {
+ if (LastStateChange.NewState != BaseState) {
// Report the end of the last new state
LastStateChange.PreviousEndLabel = CurrentEndLabel;
LastStateChange.NewStartLabel = nullptr;
- LastStateChange.NewState = NullState;
+ LastStateChange.NewState = BaseState;
// Leave CurrentEndLabel non-null to distinguish this state from end.
assert(CurrentEndLabel != nullptr);
return *this;
@@ -775,26 +760,54 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
void WinException::computeIP2StateTable(
const MachineFunction *MF, const WinEHFuncInfo &FuncInfo,
SmallVectorImpl<std::pair<const MCExpr *, int>> &IPToStateTable) {
- // Indicate that all calls from the prologue to the first invoke unwind to
- // caller. We handle this as a special case since other ranges starting at end
- // labels need to use LtmpN+1.
- MCSymbol *StartLabel = Asm->getFunctionBegin();
- assert(StartLabel && "need local function start label");
- IPToStateTable.push_back(std::make_pair(create32bitRef(StartLabel), -1));
-
- // FIXME: Do we need to emit entries for funclet base states?
- for (const auto &StateChange :
- InvokeStateChangeIterator::range(FuncInfo, *MF)) {
- // Compute the label to report as the start of this entry; use the EH start
- // label for the invoke if we have one, otherwise (this is a call which may
- // unwind to our caller and does not have an EH start label, so) use the
- // previous end label.
- const MCSymbol *ChangeLabel = StateChange.NewStartLabel;
- if (!ChangeLabel)
- ChangeLabel = StateChange.PreviousEndLabel;
- // Emit an entry indicating that PCs after 'Label' have this EH state.
+
+ for (MachineFunction::const_iterator FuncletStart = MF->begin(),
+ FuncletEnd = MF->begin(),
+ End = MF->end();
+ FuncletStart != End; FuncletStart = FuncletEnd) {
+ // Find the end of the funclet
+ while (++FuncletEnd != End) {
+ if (FuncletEnd->isEHFuncletEntry()) {
+ break;
+ }
+ }
+
+ // Don't emit ip2state entries for cleanup funclets. Any interesting
+ // exceptional actions in cleanups must be handled in a separate IR
+ // function.
+ if (FuncletStart->isCleanupFuncletEntry())
+ continue;
+
+ MCSymbol *StartLabel;
+ int BaseState;
+ if (FuncletStart == MF->begin()) {
+ BaseState = NullState;
+ StartLabel = Asm->getFunctionBegin();
+ } else {
+ auto *FuncletPad =
+ cast<FuncletPadInst>(FuncletStart->getBasicBlock()->getFirstNonPHI());
+ assert(FuncInfo.FuncletBaseStateMap.count(FuncletPad) != 0);
+ BaseState = FuncInfo.FuncletBaseStateMap.find(FuncletPad)->second;
+ StartLabel = getMCSymbolForMBB(Asm, &*FuncletStart);
+ }
+ assert(StartLabel && "need local function start label");
IPToStateTable.push_back(
- std::make_pair(getLabelPlusOne(ChangeLabel), StateChange.NewState));
+ std::make_pair(create32bitRef(StartLabel), BaseState));
+
+ for (const auto &StateChange : InvokeStateChangeIterator::range(
+ FuncInfo, FuncletStart, FuncletEnd, BaseState)) {
+ // Compute the label to report as the start of this entry; use the EH
+ // start label for the invoke if we have one, otherwise (this is a call
+ // which may unwind to our caller and does not have an EH start label, so)
+ // use the previous end label.
+ const MCSymbol *ChangeLabel = StateChange.NewStartLabel;
+ if (!ChangeLabel)
+ ChangeLabel = StateChange.PreviousEndLabel;
+ // Emit an entry indicating that PCs after 'Label' have this EH state.
+ IPToStateTable.push_back(
+ std::make_pair(getLabelPlusOne(ChangeLabel), StateChange.NewState));
+ // FIXME: assert that NewState is between CatchLow and CatchHigh.
+ }
}
}
diff --git a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
index ff0ccd415db..6ae38d3258d 100644
--- a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
+++ b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
@@ -225,12 +225,12 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
MMI.setHasEHFunclets(true);
MF->getFrameInfo()->setHasOpaqueSPAdjustment(true);
}
- if (isa<CatchEndPadInst>(I) || isa<CleanupEndPadInst>(I)) {
+ if (isa<CatchSwitchInst>(I)) {
assert(&*BB->begin() == I &&
"WinEHPrepare failed to remove PHIs from imaginary BBs");
continue;
}
- if (isa<CatchPadInst>(I) || isa<CleanupPadInst>(I))
+ if (isa<FuncletPadInst>(I))
assert(&*BB->begin() == I && "WinEHPrepare failed to demote PHIs");
}
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index dc2a57a860f..506115c7856 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -1184,21 +1184,7 @@ void SelectionDAGBuilder::visitCatchPad(const CatchPadInst &I) {
if (IsMSVCCXX || IsCoreCLR)
CatchPadMBB->setIsEHFuncletEntry();
- MachineBasicBlock *NormalDestMBB = FuncInfo.MBBMap[I.getNormalDest()];
-
- // Update machine-CFG edge.
- FuncInfo.MBB->addSuccessor(NormalDestMBB);
-
- SDValue Chain =
- DAG.getNode(ISD::CATCHPAD, getCurSDLoc(), MVT::Other, getControlRoot());
-
- // If this is not a fall-through branch or optimizations are switched off,
- // emit the branch.
- if (NormalDestMBB != NextBlock(CatchPadMBB) ||
- TM.getOptLevel() == CodeGenOpt::None)
- Chain = DAG.getNode(ISD::BR, getCurSDLoc(), MVT::Other, Chain,
- DAG.getBasicBlock(NormalDestMBB));
- DAG.setRoot(Chain);
+ DAG.setRoot(DAG.getNode(ISD::CATCHPAD, getCurSDLoc(), MVT::Other, getControlRoot()));
}
void SelectionDAGBuilder::visitCatchRet(const CatchReturnInst &I) {
@@ -1234,10 +1220,6 @@ void SelectionDAGBuilder::visitCatchRet(const CatchReturnInst &I) {
DAG.setRoot(Ret);
}
-void SelectionDAGBuilder::visitCatchEndPad(const CatchEndPadInst &I) {
- llvm_unreachable("should never codegen catchendpads");
-}
-
void SelectionDAGBuilder::visitCleanupPad(const CleanupPadInst &CPI) {
// Don't emit any special code for the cleanuppad instruction. It just marks
// the start of a funclet.
@@ -1248,8 +1230,8 @@ void SelectionDAGBuilder::visitCleanupPad(const CleanupPadInst &CPI) {
/// When an invoke or a cleanupret unwinds to the next EH pad, there are
/// many places it could ultimately go. In the IR, we have a single unwind
/// destination, but in the machine CFG, we enumerate all the possible blocks.
-/// This function skips over imaginary basic blocks that hold catchpad,
-/// terminatepad, or catchendpad instructions, and finds all the "real" machine
+/// This function skips over imaginary basic blocks that hold catchswitch or
+/// terminatepad instructions, and finds all the "real" machine
/// basic block destinations. As those destinations may not be successors of
/// EHPadBB, here we also calculate the edge probability to those destinations.
/// The passed-in Prob is the edge probability to EHPadBB.
@@ -1276,19 +1258,18 @@ static void findUnwindDestinations(
UnwindDests.emplace_back(FuncInfo.MBBMap[EHPadBB], Prob);
UnwindDests.back().first->setIsEHFuncletEntry();
break;
- } else if (const auto *CPI = dyn_cast<CatchPadInst>(Pad)) {
- // Add the catchpad handler to the possible destinations.
- UnwindDests.emplace_back(FuncInfo.MBBMap[EHPadBB], Prob);
- // In MSVC C++, catchblocks are funclets and need prologues.
- if (IsMSVCCXX || IsCoreCLR)
- UnwindDests.back().first->setIsEHFuncletEntry();
- NewEHPadBB = CPI->getUnwindDest();
- } else if (const auto *CEPI = dyn_cast<CatchEndPadInst>(Pad))
- NewEHPadBB = CEPI->getUnwindDest();
- else if (const auto *CEPI = dyn_cast<CleanupEndPadInst>(Pad))
- NewEHPadBB = CEPI->getUnwindDest();
- else
+ } else if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(Pad)) {
+ // Add the catchpad handlers to the possible destinations.
+ for (const BasicBlock *CatchPadBB : CatchSwitch->handlers()) {
+ UnwindDests.emplace_back(FuncInfo.MBBMap[CatchPadBB], Prob);
+ // For MSVC++ and the CLR, catchblocks are funclets and need prologues.
+ if (IsMSVCCXX || IsCoreCLR)
+ UnwindDests.back().first->setIsEHFuncletEntry();
+ }
+ NewEHPadBB = CatchSwitch->getUnwindDest();
+ } else {
continue;
+ }
BranchProbabilityInfo *BPI = FuncInfo.BPI;
if (BPI && NewEHPadBB)
@@ -1319,14 +1300,14 @@ void SelectionDAGBuilder::visitCleanupRet(const CleanupReturnInst &I) {
DAG.setRoot(Ret);
}
-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::visitCatchSwitch(const CatchSwitchInst &CSI) {
+ report_fatal_error("visitCatchSwitch not yet implemented!");
+}
+
void SelectionDAGBuilder::visitRet(const ReturnInst &I) {
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
auto &DL = DAG.getDataLayout();
@@ -2124,8 +2105,8 @@ void SelectionDAGBuilder::visitBitTestCase(BitTestBlock &BB,
void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) {
MachineBasicBlock *InvokeMBB = FuncInfo.MBB;
- // Retrieve successors. Look through artificial IR level blocks like catchpads
- // and catchendpads for successors.
+ // Retrieve successors. Look through artificial IR level blocks like
+ // catchswitch for successors.
MachineBasicBlock *Return = FuncInfo.MBBMap[I.getSuccessor(0)];
const BasicBlock *EHPadBB = I.getSuccessor(1);
@@ -5367,8 +5348,10 @@ SelectionDAGBuilder::lowerInvokable(TargetLowering::CallLoweringInfo &CLI,
// Inform MachineModuleInfo of range.
if (MMI.hasEHFunclets()) {
+ assert(CLI.CS);
WinEHFuncInfo *EHInfo = DAG.getMachineFunction().getWinEHFuncInfo();
- EHInfo->addIPToStateRange(EHPadBB, BeginLabel, EndLabel);
+ EHInfo->addIPToStateRange(cast<InvokeInst>(CLI.CS->getInstruction()),
+ BeginLabel, EndLabel);
} else {
MMI.addInvoke(FuncInfo.MBBMap[EHPadBB], BeginLabel, EndLabel);
}
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
index 1171f0aad00..4f8e8132c4a 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
+++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
@@ -736,9 +736,8 @@ private:
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 visitCatchSwitch(const CatchSwitchInst &I);
void visitCatchRet(const CatchReturnInst &I);
void visitCatchPad(const CatchPadInst &I);
void visitTerminatePad(const TerminatePadInst &TPI);
diff --git a/lib/CodeGen/TargetLoweringBase.cpp b/lib/CodeGen/TargetLoweringBase.cpp
index c5972263046..74a42f8ee34 100644
--- a/lib/CodeGen/TargetLoweringBase.cpp
+++ b/lib/CodeGen/TargetLoweringBase.cpp
@@ -1570,13 +1570,12 @@ int TargetLoweringBase::InstructionOpcodeToISD(unsigned Opcode) const {
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 CatchPad: return 0;
- case TerminatePad: return 0;
- case CleanupPad: return 0;
+ case CatchPad: return 0;
+ case CatchSwitch: return 0;
+ case TerminatePad: return 0;
+ case CleanupPad: return 0;
case Add: return ISD::ADD;
case FAdd: return ISD::FADD;
case Sub: return ISD::SUB;
diff --git a/lib/CodeGen/WinEHPrepare.cpp b/lib/CodeGen/WinEHPrepare.cpp
index dee4b870434..9f199a15718 100644
--- a/lib/CodeGen/WinEHPrepare.cpp
+++ b/lib/CodeGen/WinEHPrepare.cpp
@@ -17,7 +17,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/Passes.h"
-#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/MapVector.h"
#include "llvm/Analysis/CFG.h"
#include "llvm/Analysis/EHPersonalities.h"
#include "llvm/CodeGen/WinEHFuncInfo.h"
@@ -69,27 +69,12 @@ private:
AllocaInst *insertPHILoads(PHINode *PN, Function &F);
void replaceUseWithLoad(Value *V, Use &U, AllocaInst *&SpillSlot,
DenseMap<BasicBlock *, Value *> &Loads, Function &F);
- bool prepareExplicitEH(Function &F,
- SmallVectorImpl<BasicBlock *> &EntryBlocks);
+ bool prepareExplicitEH(Function &F);
void replaceTerminatePadWithCleanup(Function &F);
- void colorFunclets(Function &F, SmallVectorImpl<BasicBlock *> &EntryBlocks);
- void resolveFuncletAncestry(Function &F,
- SmallVectorImpl<BasicBlock *> &EntryBlocks);
- void resolveFuncletAncestryForPath(
- Function &F, SmallVectorImpl<BasicBlock *> &FuncletPath,
- std::map<BasicBlock *, BasicBlock *> &IdentityMap);
- void makeFuncletEdgeUnreachable(BasicBlock *Parent, BasicBlock *Child);
- BasicBlock *cloneFuncletForParent(Function &F, BasicBlock *FuncletEntry,
- BasicBlock *Parent);
- void updateTerminatorsAfterFuncletClone(
- Function &F, BasicBlock *OrigFunclet, BasicBlock *CloneFunclet,
- BasicBlock *OrigBlock, BasicBlock *CloneBlock, BasicBlock *CloneParent,
- ValueToValueMapTy &VMap,
- std::map<BasicBlock *, BasicBlock *> &Orig2Clone);
+ void colorFunclets(Function &F);
void demotePHIsOnFunclets(Function &F);
- void cloneCommonBlocks(Function &F,
- SmallVectorImpl<BasicBlock *> &EntryBlocks);
+ void cloneCommonBlocks(Function &F);
void removeImplausibleTerminators(Function &F);
void cleanupPreparedFunclets(Function &F);
void verifyPreparedFunclets(Function &F);
@@ -97,20 +82,8 @@ private:
// All fields are reset by runOnFunction.
EHPersonality Personality = EHPersonality::Unknown;
- std::map<BasicBlock *, SetVector<BasicBlock *>> BlockColors;
- std::map<BasicBlock *, std::set<BasicBlock *>> FuncletBlocks;
- std::map<BasicBlock *, std::vector<BasicBlock *>> FuncletChildren;
- std::map<BasicBlock *, std::vector<BasicBlock *>> FuncletParents;
-
- // This is a flag that indicates an uncommon situation where we need to
- // clone funclets has been detected.
- bool FuncletCloningRequired = false;
- // When a funclet with multiple parents contains a catchret, the block to
- // which it returns will be cloned so that there is a copy in each parent
- // but one of the copies will not be properly linked to the catchret and
- // in most cases will have no predecessors. This double map allows us
- // to find these cloned blocks when we clone the child funclet.
- std::map<BasicBlock *, std::map<BasicBlock *, BasicBlock*>> EstrangedBlocks;
+ DenseMap<BasicBlock *, ColorVector> BlockColors;
+ MapVector<BasicBlock *, std::vector<BasicBlock *>> FuncletBlocks;
};
} // end anonymous namespace
@@ -123,21 +96,6 @@ FunctionPass *llvm::createWinEHPass(const TargetMachine *TM) {
return new WinEHPrepare(TM);
}
-static void findFuncletEntryPoints(Function &Fn,
- SmallVectorImpl<BasicBlock *> &EntryBlocks) {
- EntryBlocks.push_back(&Fn.getEntryBlock());
- for (BasicBlock &BB : Fn) {
- Instruction *First = BB.getFirstNonPHI();
- if (!First->isEHPad())
- continue;
- assert(!isa<LandingPadInst>(First) &&
- "landingpad cannot be used with funclet EH personality");
- // Find EH pad blocks that represent funclet start points.
- if (!isa<CatchEndPadInst>(First) && !isa<CleanupEndPadInst>(First))
- EntryBlocks.push_back(&BB);
- }
-}
-
bool WinEHPrepare::runOnFunction(Function &Fn) {
if (!Fn.hasPersonalityFn())
return false;
@@ -149,14 +107,7 @@ bool WinEHPrepare::runOnFunction(Function &Fn) {
if (!isFuncletEHPersonality(Personality))
return false;
- // Remove unreachable blocks. It is not valuable to assign them a color and
- // their existence can trick us into thinking values are alive when they are
- // not.
- removeUnreachableBlocks(Fn);
-
- SmallVector<BasicBlock *, 4> EntryBlocks;
- findFuncletEntryPoints(Fn, EntryBlocks);
- return prepareExplicitEH(Fn, EntryBlocks);
+ return prepareExplicitEH(Fn);
}
bool WinEHPrepare::doFinalization(Module &M) { return false; }
@@ -198,117 +149,142 @@ static void addTryBlockMapEntry(WinEHFuncInfo &FuncInfo, int TryLow,
FuncInfo.TryBlockMap.push_back(TBME);
}
-static const CatchPadInst *getSingleCatchPadPredecessor(const BasicBlock *BB) {
- for (const BasicBlock *PredBlock : predecessors(BB))
- if (auto *CPI = dyn_cast<CatchPadInst>(PredBlock->getFirstNonPHI()))
- return CPI;
+static BasicBlock *getCleanupRetUnwindDest(const CleanupPadInst *CleanupPad) {
+ for (const User *U : CleanupPad->users())
+ if (const auto *CRI = dyn_cast<CleanupReturnInst>(U))
+ return CRI->getUnwindDest();
return nullptr;
}
-/// Find all the catchpads that feed directly into the catchendpad. Frontends
-/// using this personality should ensure that each catchendpad and catchpad has
-/// one or zero catchpad predecessors.
-///
-/// The following C++ generates the IR after it:
-/// try {
-/// } catch (A) {
-/// } catch (B) {
-/// }
-///
-/// IR:
-/// %catchpad.A
-/// catchpad [i8* A typeinfo]
-/// to label %catch.A unwind label %catchpad.B
-/// %catchpad.B
-/// catchpad [i8* B typeinfo]
-/// to label %catch.B unwind label %endcatches
-/// %endcatches
-/// catchendblock unwind to caller
-static void
-findCatchPadsForCatchEndPad(const BasicBlock *CatchEndBB,
- SmallVectorImpl<const CatchPadInst *> &Handlers) {
- const CatchPadInst *CPI = getSingleCatchPadPredecessor(CatchEndBB);
- while (CPI) {
- Handlers.push_back(CPI);
- CPI = getSingleCatchPadPredecessor(CPI->getParent());
+static void calculateStateNumbersForInvokes(const Function *Fn,
+ WinEHFuncInfo &FuncInfo) {
+ auto *F = const_cast<Function *>(Fn);
+ DenseMap<BasicBlock *, ColorVector> BlockColors = colorEHFunclets(*F);
+ for (BasicBlock &BB : *F) {
+ auto *II = dyn_cast<InvokeInst>(BB.getTerminator());
+ if (!II)
+ continue;
+
+ auto &BBColors = BlockColors[&BB];
+ assert(BBColors.size() == 1 &&
+ "multi-color BB not removed by preparation");
+ BasicBlock *FuncletEntryBB = BBColors.front();
+
+ BasicBlock *FuncletUnwindDest;
+ auto *FuncletPad =
+ dyn_cast<FuncletPadInst>(FuncletEntryBB->getFirstNonPHI());
+ assert(FuncletPad || FuncletEntryBB == &Fn->getEntryBlock());
+ if (!FuncletPad)
+ FuncletUnwindDest = nullptr;
+ else if (auto *CatchPad = dyn_cast<CatchPadInst>(FuncletPad))
+ FuncletUnwindDest = CatchPad->getCatchSwitch()->getUnwindDest();
+ else if (auto *CleanupPad = dyn_cast<CleanupPadInst>(FuncletPad))
+ FuncletUnwindDest = getCleanupRetUnwindDest(CleanupPad);
+ else
+ llvm_unreachable("unexpected funclet pad!");
+
+ BasicBlock *InvokeUnwindDest = II->getUnwindDest();
+ int BaseState = -1;
+ if (FuncletUnwindDest == InvokeUnwindDest) {
+ auto BaseStateI = FuncInfo.FuncletBaseStateMap.find(FuncletPad);
+ if (BaseStateI != FuncInfo.FuncletBaseStateMap.end())
+ BaseState = BaseStateI->second;
+ }
+
+ if (BaseState != -1) {
+ FuncInfo.InvokeStateMap[II] = BaseState;
+ } else {
+ Instruction *PadInst = InvokeUnwindDest->getFirstNonPHI();
+ assert(FuncInfo.EHPadStateMap.count(PadInst) && "EH Pad has no state!");
+ FuncInfo.InvokeStateMap[II] = FuncInfo.EHPadStateMap[PadInst];
+ }
}
- // We've pushed these back into reverse source order. Reverse them to get
- // the list back into source order.
- std::reverse(Handlers.begin(), Handlers.end());
}
// Given BB which ends in an unwind edge, return the EHPad that this BB belongs
// to. If the unwind edge came from an invoke, return null.
-static const BasicBlock *getEHPadFromPredecessor(const BasicBlock *BB) {
+static const BasicBlock *getEHPadFromPredecessor(const BasicBlock *BB,
+ Value *ParentPad) {
const TerminatorInst *TI = BB->getTerminator();
if (isa<InvokeInst>(TI))
return nullptr;
- if (TI->isEHPad())
+ if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(TI)) {
+ if (CatchSwitch->getParentPad() != ParentPad)
+ return nullptr;
return BB;
- return cast<CleanupReturnInst>(TI)->getCleanupPad()->getParent();
+ }
+ assert(!TI->isEHPad() && "unexpected EHPad!");
+ auto *CleanupPad = cast<CleanupReturnInst>(TI)->getCleanupPad();
+ if (CleanupPad->getParentPad() != ParentPad)
+ return nullptr;
+ return CleanupPad->getParent();
}
-static void calculateExplicitCXXStateNumbers(WinEHFuncInfo &FuncInfo,
- const BasicBlock &BB,
- int ParentState) {
- assert(BB.isEHPad());
- const Instruction *FirstNonPHI = BB.getFirstNonPHI();
- // All catchpad instructions will be handled when we process their
- // respective catchendpad instruction.
- if (isa<CatchPadInst>(FirstNonPHI))
- return;
+static void calculateCXXStateNumbers(WinEHFuncInfo &FuncInfo,
+ const Instruction *FirstNonPHI,
+ int ParentState) {
+ const BasicBlock *BB = FirstNonPHI->getParent();
+ assert(BB->isEHPad() && "not a funclet!");
+
+ if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(FirstNonPHI)) {
+ assert(FuncInfo.EHPadStateMap.count(CatchSwitch) == 0 &&
+ "shouldn't revist catch funclets!");
- if (isa<CatchEndPadInst>(FirstNonPHI)) {
SmallVector<const CatchPadInst *, 2> Handlers;
- findCatchPadsForCatchEndPad(&BB, Handlers);
- const BasicBlock *FirstTryPad = Handlers.front()->getParent();
+ for (const BasicBlock *CatchPadBB : CatchSwitch->handlers()) {
+ auto *CatchPad = cast<CatchPadInst>(CatchPadBB->getFirstNonPHI());
+ Handlers.push_back(CatchPad);
+ }
int TryLow = addUnwindMapEntry(FuncInfo, ParentState, nullptr);
- FuncInfo.EHPadStateMap[Handlers.front()] = TryLow;
- for (const BasicBlock *PredBlock : predecessors(FirstTryPad))
- if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
- calculateExplicitCXXStateNumbers(FuncInfo, *PredBlock, TryLow);
+ FuncInfo.EHPadStateMap[CatchSwitch] = TryLow;
+ for (const BasicBlock *PredBlock : predecessors(BB))
+ if ((PredBlock = getEHPadFromPredecessor(PredBlock,
+ CatchSwitch->getParentPad())))
+ calculateCXXStateNumbers(FuncInfo, PredBlock->getFirstNonPHI(),
+ TryLow);
int CatchLow = addUnwindMapEntry(FuncInfo, ParentState, nullptr);
// catchpads are separate funclets in C++ EH due to the way rethrow works.
- // In SEH, they aren't, so no invokes will unwind to the catchendpad.
- FuncInfo.EHPadStateMap[FirstNonPHI] = CatchLow;
int TryHigh = CatchLow - 1;
- for (const BasicBlock *PredBlock : predecessors(&BB))
- if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
- calculateExplicitCXXStateNumbers(FuncInfo, *PredBlock, CatchLow);
+ for (const auto *CatchPad : Handlers) {
+ FuncInfo.FuncletBaseStateMap[CatchPad] = CatchLow;
+ for (const User *U : CatchPad->users()) {
+ const auto *UserI = cast<Instruction>(U);
+ if (UserI->isEHPad())
+ calculateCXXStateNumbers(FuncInfo, UserI, CatchLow);
+ }
+ }
int CatchHigh = FuncInfo.getLastStateNumber();
addTryBlockMapEntry(FuncInfo, TryLow, TryHigh, CatchHigh, Handlers);
- DEBUG(dbgs() << "TryLow[" << FirstTryPad->getName() << "]: " << TryLow
+ DEBUG(dbgs() << "TryLow[" << BB->getName() << "]: " << TryLow << '\n');
+ DEBUG(dbgs() << "TryHigh[" << BB->getName() << "]: " << TryHigh << '\n');
+ DEBUG(dbgs() << "CatchHigh[" << BB->getName() << "]: " << CatchHigh
<< '\n');
- DEBUG(dbgs() << "TryHigh[" << FirstTryPad->getName() << "]: " << TryHigh
- << '\n');
- DEBUG(dbgs() << "CatchHigh[" << FirstTryPad->getName() << "]: " << CatchHigh
- << '\n');
- } else if (isa<CleanupPadInst>(FirstNonPHI)) {
- // A cleanup can have multiple exits; don't re-process after the first.
- if (FuncInfo.EHPadStateMap.count(FirstNonPHI))
+ } else {
+ auto *CleanupPad = cast<CleanupPadInst>(FirstNonPHI);
+
+ // It's possible for a cleanup to be visited twice: it might have multiple
+ // cleanupret instructions.
+ if (FuncInfo.EHPadStateMap.count(CleanupPad))
return;
- int CleanupState = addUnwindMapEntry(FuncInfo, ParentState, &BB);
- FuncInfo.EHPadStateMap[FirstNonPHI] = CleanupState;
+
+ int CleanupState = addUnwindMapEntry(FuncInfo, ParentState, BB);
+ FuncInfo.EHPadStateMap[CleanupPad] = CleanupState;
DEBUG(dbgs() << "Assigning state #" << CleanupState << " to BB "
- << BB.getName() << '\n');
- for (const BasicBlock *PredBlock : predecessors(&BB))
- if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
- calculateExplicitCXXStateNumbers(FuncInfo, *PredBlock, CleanupState);
- } else if (auto *CEPI = dyn_cast<CleanupEndPadInst>(FirstNonPHI)) {
- // Propagate ParentState to the cleanuppad in case it doesn't have
- // any cleanuprets.
- BasicBlock *CleanupBlock = CEPI->getCleanupPad()->getParent();
- calculateExplicitCXXStateNumbers(FuncInfo, *CleanupBlock, ParentState);
- // Anything unwinding through CleanupEndPadInst is in ParentState.
- FuncInfo.EHPadStateMap[FirstNonPHI] = ParentState;
- for (const BasicBlock *PredBlock : predecessors(&BB))
- if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
- calculateExplicitCXXStateNumbers(FuncInfo, *PredBlock, ParentState);
- } else if (isa<TerminatePadInst>(FirstNonPHI)) {
- report_fatal_error("Not yet implemented!");
- } else {
- llvm_unreachable("unexpected EH Pad!");
+ << BB->getName() << '\n');
+ for (const BasicBlock *PredBlock : predecessors(BB)) {
+ if ((PredBlock = getEHPadFromPredecessor(PredBlock,
+ CleanupPad->getParentPad()))) {
+ calculateCXXStateNumbers(FuncInfo, PredBlock->getFirstNonPHI(),
+ CleanupState);
+ }
+ }
+ for (const User *U : CleanupPad->users()) {
+ const auto *UserI = cast<Instruction>(U);
+ if (UserI->isEHPad())
+ report_fatal_error("Cleanup funclets for the MSVC++ personality cannot "
+ "contain exceptional actions");
+ }
}
}
@@ -334,94 +310,84 @@ static int addSEHFinally(WinEHFuncInfo &FuncInfo, int ParentState,
return FuncInfo.SEHUnwindMap.size() - 1;
}
-static void calculateExplicitSEHStateNumbers(WinEHFuncInfo &FuncInfo,
- const BasicBlock &BB,
- int ParentState) {
- assert(BB.isEHPad());
- const Instruction *FirstNonPHI = BB.getFirstNonPHI();
- // All catchpad instructions will be handled when we process their
- // respective catchendpad instruction.
- if (isa<CatchPadInst>(FirstNonPHI))
- return;
+static void calculateSEHStateNumbers(WinEHFuncInfo &FuncInfo,
+ const Instruction *FirstNonPHI,
+ int ParentState) {
+ const BasicBlock *BB = FirstNonPHI->getParent();
+ assert(BB->isEHPad() && "no a funclet!");
+
+ if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(FirstNonPHI)) {
+ assert(FuncInfo.EHPadStateMap.count(CatchSwitch) == 0 &&
+ "shouldn't revist catch funclets!");
- if (isa<CatchEndPadInst>(FirstNonPHI)) {
// Extract the filter function and the __except basic block and create a
// state for them.
- SmallVector<const CatchPadInst *, 1> Handlers;
- findCatchPadsForCatchEndPad(&BB, Handlers);
- assert(Handlers.size() == 1 &&
+ assert(CatchSwitch->getNumHandlers() == 1 &&
"SEH doesn't have multiple handlers per __try");
- const CatchPadInst *CPI = Handlers.front();
- const BasicBlock *CatchPadBB = CPI->getParent();
+ const auto *CatchPad =
+ cast<CatchPadInst>((*CatchSwitch->handler_begin())->getFirstNonPHI());
+ const BasicBlock *CatchPadBB = CatchPad->getParent();
const Constant *FilterOrNull =
- cast<Constant>(CPI->getArgOperand(0)->stripPointerCasts());
+ cast<Constant>(CatchPad->getArgOperand(0)->stripPointerCasts());
const Function *Filter = dyn_cast<Function>(FilterOrNull);
assert((Filter || FilterOrNull->isNullValue()) &&
"unexpected filter value");
int TryState = addSEHExcept(FuncInfo, ParentState, Filter, CatchPadBB);
// Everything in the __try block uses TryState as its parent state.
- FuncInfo.EHPadStateMap[CPI] = TryState;
+ FuncInfo.EHPadStateMap[CatchSwitch] = TryState;
DEBUG(dbgs() << "Assigning state #" << TryState << " to BB "
<< CatchPadBB->getName() << '\n');
- for (const BasicBlock *PredBlock : predecessors(CatchPadBB))
- if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
- calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, TryState);
+ for (const BasicBlock *PredBlock : predecessors(BB))
+ if ((PredBlock = getEHPadFromPredecessor(PredBlock,
+ CatchSwitch->getParentPad())))
+ calculateSEHStateNumbers(FuncInfo, PredBlock->getFirstNonPHI(),
+ TryState);
// Everything in the __except block unwinds to ParentState, just like code
// outside the __try.
- FuncInfo.EHPadStateMap[FirstNonPHI] = ParentState;
- DEBUG(dbgs() << "Assigning state #" << ParentState << " to BB "
- << BB.getName() << '\n');
- for (const BasicBlock *PredBlock : predecessors(&BB))
- if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
- calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, ParentState);
- } else if (isa<CleanupPadInst>(FirstNonPHI)) {
- // A cleanup can have multiple exits; don't re-process after the first.
- if (FuncInfo.EHPadStateMap.count(FirstNonPHI))
+ for (const User *U : CatchPad->users()) {
+ const auto *UserI = cast<Instruction>(U);
+ if (UserI->isEHPad()) {
+ calculateSEHStateNumbers(FuncInfo, UserI, ParentState);
+ }
+ }
+ } else {
+ auto *CleanupPad = cast<CleanupPadInst>(FirstNonPHI);
+
+ // It's possible for a cleanup to be visited twice: it might have multiple
+ // cleanupret instructions.
+ if (FuncInfo.EHPadStateMap.count(CleanupPad))
return;
- int CleanupState = addSEHFinally(FuncInfo, ParentState, &BB);
- FuncInfo.EHPadStateMap[FirstNonPHI] = CleanupState;
+
+ int CleanupState = addSEHFinally(FuncInfo, ParentState, BB);
+ FuncInfo.EHPadStateMap[CleanupPad] = CleanupState;
DEBUG(dbgs() << "Assigning state #" << CleanupState << " to BB "
- << BB.getName() << '\n');
- for (const BasicBlock *PredBlock : predecessors(&BB))
- if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
- calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, CleanupState);
- } else if (auto *CEPI = dyn_cast<CleanupEndPadInst>(FirstNonPHI)) {
- // Propagate ParentState to the cleanuppad in case it doesn't have
- // any cleanuprets.
- BasicBlock *CleanupBlock = CEPI->getCleanupPad()->getParent();
- calculateExplicitSEHStateNumbers(FuncInfo, *CleanupBlock, ParentState);
- // Anything unwinding through CleanupEndPadInst is in ParentState.
- FuncInfo.EHPadStateMap[FirstNonPHI] = ParentState;
- DEBUG(dbgs() << "Assigning state #" << ParentState << " to BB "
- << BB.getName() << '\n');
- for (const BasicBlock *PredBlock : predecessors(&BB))
- if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
- calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, ParentState);
- } else if (isa<TerminatePadInst>(FirstNonPHI)) {
- report_fatal_error("Not yet implemented!");
- } else {
- llvm_unreachable("unexpected EH Pad!");
+ << BB->getName() << '\n');
+ for (const BasicBlock *PredBlock : predecessors(BB))
+ if ((PredBlock =
+ getEHPadFromPredecessor(PredBlock, CleanupPad->getParentPad())))
+ calculateSEHStateNumbers(FuncInfo, PredBlock->getFirstNonPHI(),
+ CleanupState);
+ for (const User *U : CleanupPad->users()) {
+ const auto *UserI = cast<Instruction>(U);
+ if (UserI->isEHPad())
+ report_fatal_error("Cleanup funclets for the SEH personality cannot "
+ "contain exceptional actions");
+ }
}
}
-/// Check if the EH Pad unwinds to caller. Cleanups are a little bit of a
-/// special case because we have to look at the cleanupret instruction that uses
-/// the cleanuppad.
-static bool doesEHPadUnwindToCaller(const Instruction *EHPad) {
- auto *CPI = dyn_cast<CleanupPadInst>(EHPad);
- if (!CPI)
- return EHPad->mayThrow();
-
- // This cleanup does not return or unwind, so we say it unwinds to caller.
- if (CPI->use_empty())
- return true;
-
- const Instruction *User = CPI->user_back();
- if (auto *CRI = dyn_cast<CleanupReturnInst>(User))
- return CRI->unwindsToCaller();
- return cast<CleanupEndPadInst>(User)->unwindsToCaller();
+static bool isTopLevelPadForMSVC(const Instruction *EHPad) {
+ if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(EHPad))
+ return isa<ConstantTokenNone>(CatchSwitch->getParentPad()) &&
+ CatchSwitch->unwindsToCaller();
+ if (auto *CleanupPad = dyn_cast<CleanupPadInst>(EHPad))
+ return isa<ConstantTokenNone>(CleanupPad->getParentPad()) &&
+ getCleanupRetUnwindDest(CleanupPad) == nullptr;
+ if (isa<CatchPadInst>(EHPad))
+ return false;
+ llvm_unreachable("unexpected EHPad!");
}
void llvm::calculateSEHStateNumbers(const Function *Fn,
@@ -431,10 +397,15 @@ void llvm::calculateSEHStateNumbers(const Function *Fn,
return;
for (const BasicBlock &BB : *Fn) {
- if (!BB.isEHPad() || !doesEHPadUnwindToCaller(BB.getFirstNonPHI()))
+ if (!BB.isEHPad())
+ continue;
+ const Instruction *FirstNonPHI = BB.getFirstNonPHI();
+ if (!isTopLevelPadForMSVC(FirstNonPHI))
continue;
- calculateExplicitSEHStateNumbers(FuncInfo, BB, -1);
+ ::calculateSEHStateNumbers(FuncInfo, FirstNonPHI, -1);
}
+
+ calculateStateNumbersForInvokes(Fn, FuncInfo);
}
void llvm::calculateWinCXXEHStateNumbers(const Function *Fn,
@@ -446,13 +417,13 @@ void llvm::calculateWinCXXEHStateNumbers(const Function *Fn,
for (const BasicBlock &BB : *Fn) {
if (!BB.isEHPad())
continue;
- if (BB.isLandingPad())
- report_fatal_error("MSVC C++ EH cannot use landingpads");
const Instruction *FirstNonPHI = BB.getFirstNonPHI();
- if (!doesEHPadUnwindToCaller(FirstNonPHI))
+ if (!isTopLevelPadForMSVC(FirstNonPHI))
continue;
- calculateExplicitCXXStateNumbers(FuncInfo, BB, -1);
+ calculateCXXStateNumbers(FuncInfo, FirstNonPHI, -1);
}
+
+ calculateStateNumbersForInvokes(Fn, FuncInfo);
}
static int addClrEHHandler(WinEHFuncInfo &FuncInfo, int ParentState,
@@ -483,7 +454,7 @@ void llvm::calculateClrEHStateNumbers(const Function *Fn,
if (BB.isLandingPad())
report_fatal_error("CoreCLR EH cannot use landingpads");
const Instruction *FirstNonPHI = BB.getFirstNonPHI();
- if (!doesEHPadUnwindToCaller(FirstNonPHI))
+ if (!isTopLevelPadForMSVC(FirstNonPHI))
continue;
// queue this with sentinel parent state -1 to mean unwind to caller.
Worklist.emplace_back(FirstNonPHI, -1);
@@ -494,16 +465,11 @@ void llvm::calculateClrEHStateNumbers(const Function *Fn,
int ParentState;
std::tie(Pad, ParentState) = Worklist.pop_back_val();
+ Value *ParentPad;
int PredState;
- if (const CleanupEndPadInst *EndPad = dyn_cast<CleanupEndPadInst>(Pad)) {
- FuncInfo.EHPadStateMap[EndPad] = ParentState;
- // Queue the cleanuppad, in case it doesn't have a cleanupret.
- Worklist.emplace_back(EndPad->getCleanupPad(), ParentState);
- // Preds of the endpad should get the parent state.
- PredState = ParentState;
- } else if (const CleanupPadInst *Cleanup = dyn_cast<CleanupPadInst>(Pad)) {
+ if (const CleanupPadInst *Cleanup = dyn_cast<CleanupPadInst>(Pad)) {
// A cleanup can have multiple exits; don't re-process after the first.
- if (FuncInfo.EHPadStateMap.count(Pad))
+ if (FuncInfo.EHPadStateMap.count(Cleanup))
continue;
// CoreCLR personality uses arity to distinguish faults from finallies.
const BasicBlock *PadBlock = Cleanup->getParent();
@@ -514,30 +480,47 @@ void llvm::calculateClrEHStateNumbers(const Function *Fn,
addClrEHHandler(FuncInfo, ParentState, HandlerType, 0, PadBlock);
FuncInfo.EHPadStateMap[Cleanup] = NewState;
// Propagate the new state to all preds of the cleanup
+ ParentPad = Cleanup->getParentPad();
PredState = NewState;
- } else if (const CatchEndPadInst *EndPad = dyn_cast<CatchEndPadInst>(Pad)) {
- FuncInfo.EHPadStateMap[EndPad] = ParentState;
- // Preds of the endpad should get the parent state.
- PredState = ParentState;
- } else if (const CatchPadInst *Catch = dyn_cast<CatchPadInst>(Pad)) {
- const BasicBlock *PadBlock = Catch->getParent();
- uint32_t TypeToken = static_cast<uint32_t>(
- cast<ConstantInt>(Catch->getArgOperand(0))->getZExtValue());
- int NewState = addClrEHHandler(FuncInfo, ParentState,
- ClrHandlerType::Catch, TypeToken, PadBlock);
- FuncInfo.EHPadStateMap[Catch] = NewState;
- // Preds of the catch get its state
+ } else if (const auto *CatchSwitch = dyn_cast<CatchSwitchInst>(Pad)) {
+ SmallVector<const CatchPadInst *, 1> Handlers;
+ for (const BasicBlock *CatchPadBB : CatchSwitch->handlers()) {
+ const auto *Catch = cast<CatchPadInst>(CatchPadBB->getFirstNonPHI());
+ Handlers.push_back(Catch);
+ }
+ FuncInfo.EHPadStateMap[CatchSwitch] = ParentState;
+ int NewState = ParentState;
+ for (auto HandlerI = Handlers.rbegin(), HandlerE = Handlers.rend();
+ HandlerI != HandlerE; ++HandlerI) {
+ const CatchPadInst *Catch = *HandlerI;
+ const BasicBlock *PadBlock = Catch->getParent();
+ uint32_t TypeToken = static_cast<uint32_t>(
+ cast<ConstantInt>(Catch->getArgOperand(0))->getZExtValue());
+ NewState = addClrEHHandler(FuncInfo, NewState, ClrHandlerType::Catch,
+ TypeToken, PadBlock);
+ FuncInfo.EHPadStateMap[Catch] = NewState;
+ }
+ for (const auto *CatchPad : Handlers) {
+ for (const User *U : CatchPad->users()) {
+ const auto *UserI = cast<Instruction>(U);
+ if (UserI->isEHPad())
+ Worklist.emplace_back(UserI, ParentState);
+ }
+ }
PredState = NewState;
+ ParentPad = CatchSwitch->getParentPad();
} else {
llvm_unreachable("Unexpected EH pad");
}
// Queue all predecessors with the given state
for (const BasicBlock *Pred : predecessors(Pad->getParent())) {
- if ((Pred = getEHPadFromPredecessor(Pred)))
+ if ((Pred = getEHPadFromPredecessor(Pred, ParentPad)))
Worklist.emplace_back(Pred->getFirstNonPHI(), PredState);
}
}
+
+ calculateStateNumbersForInvokes(Fn, FuncInfo);
}
void WinEHPrepare::replaceTerminatePadWithCleanup(Function &F) {
@@ -559,8 +542,9 @@ void WinEHPrepare::replaceTerminatePadWithCleanup(Function &F) {
"C++ personalities!");
// Insert the cleanuppad instruction.
- auto *CPI = CleanupPadInst::Create(
- BB.getContext(), {}, Twine("terminatepad.for.", BB.getName()), &BB);
+ auto *CPI =
+ CleanupPadInst::Create(TPI->getParentPad(), {},
+ Twine("terminatepad.for.", BB.getName()), &BB);
// Insert the call to the terminate instruction.
auto *CallTerminate = CallInst::Create(TerminateFn, {}, &BB);
@@ -578,980 +562,32 @@ void WinEHPrepare::replaceTerminatePadWithCleanup(Function &F) {
}
}
-static void
-colorFunclets(Function &F, SmallVectorImpl<BasicBlock *> &EntryBlocks,
- std::map<BasicBlock *, SetVector<BasicBlock *>> &BlockColors,
- std::map<BasicBlock *, std::set<BasicBlock *>> &FuncletBlocks) {
- SmallVector<std::pair<BasicBlock *, BasicBlock *>, 16> Worklist;
- BasicBlock *EntryBlock = &F.getEntryBlock();
-
- // Build up the color map, which maps each block to its set of 'colors'.
- // For any block B, the "colors" of B are the set of funclets F (possibly
- // including a root "funclet" representing the main function), such that
- // F will need to directly contain B or a copy of B (where the term "directly
- // contain" is used to distinguish from being "transitively contained" in
- // a nested funclet).
- // Use a CFG walk driven by a worklist of (block, color) pairs. The "color"
- // sets attached during this processing to a block which is the entry of some
- // funclet F is actually the set of F's parents -- i.e. the union of colors
- // of all predecessors of F's entry. For all other blocks, the color sets
- // are as defined above. A post-pass fixes up the block color map to reflect
- // the same sense of "color" for funclet entries as for other blocks.
-
- DEBUG_WITH_TYPE("winehprepare-coloring", dbgs() << "\nColoring funclets for "
- << F.getName() << "\n");
-
- Worklist.push_back({EntryBlock, EntryBlock});
-
- while (!Worklist.empty()) {
- BasicBlock *Visiting;
- BasicBlock *Color;
- std::tie(Visiting, Color) = Worklist.pop_back_val();
- DEBUG_WITH_TYPE("winehprepare-coloring",
- dbgs() << "Visiting " << Visiting->getName() << ", "
- << Color->getName() << "\n");
- Instruction *VisitingHead = Visiting->getFirstNonPHI();
- 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 (i.e. successors of rets/endpads) with the parent color.
- // Skip any exits that are catchendpads, since the parent color must then
- // represent one of the catches chained to that catchendpad, but the
- // catchendpad should get the color of the common parent of all its
- // chained catches (i.e. the grandparent color of the current pad).
- // We don't need to worry abou catchendpads going unvisited, since the
- // catches chained to them must have unwind edges to them by which we will
- // visit them.
- for (User *U : VisitingHead->users()) {
- if (auto *Exit = dyn_cast<TerminatorInst>(U)) {
- for (BasicBlock *Succ : successors(Exit->getParent()))
- if (!isa<CatchEndPadInst>(*Succ->getFirstNonPHI()))
- if (BlockColors[Succ].insert(Color)) {
- DEBUG_WITH_TYPE("winehprepare-coloring",
- dbgs() << " Assigned color \'"
- << Color->getName() << "\' to block \'"
- << Succ->getName() << "\'.\n");
- Worklist.push_back({Succ, Color});
- }
- }
- }
- // Handle CatchPad specially since its successors need different colors.
- if (CatchPadInst *CatchPad = dyn_cast<CatchPadInst>(VisitingHead)) {
- // Visit the normal successor with the color of the new EH pad, and
- // visit the unwind successor with the color of the parent.
- BasicBlock *NormalSucc = CatchPad->getNormalDest();
- if (BlockColors[NormalSucc].insert(Visiting)) {
- DEBUG_WITH_TYPE("winehprepare-coloring",
- dbgs() << " Assigned color \'" << Visiting->getName()
- << "\' to block \'" << NormalSucc->getName()
- << "\'.\n");
- Worklist.push_back({NormalSucc, Visiting});
- }
- BasicBlock *UnwindSucc = CatchPad->getUnwindDest();
- if (BlockColors[UnwindSucc].insert(Color)) {
- DEBUG_WITH_TYPE("winehprepare-coloring",
- dbgs() << " Assigned color \'" << Color->getName()
- << "\' to block \'" << UnwindSucc->getName()
- << "\'.\n");
- Worklist.push_back({UnwindSucc, Color});
- }
- continue;
- }
- // Switch color to the current node, except for terminate pads which
- // have no bodies and only unwind successors and so need their successors
- // visited with the color of the parent.
- if (!isa<TerminatePadInst>(VisitingHead))
- Color = Visiting;
- } else {
- // Note that this is a member of the given color.
- FuncletBlocks[Color].insert(Visiting);
- }
-
- TerminatorInst *Terminator = Visiting->getTerminator();
- if (isa<CleanupReturnInst>(Terminator) ||
- isa<CatchReturnInst>(Terminator) ||
- isa<CleanupEndPadInst>(Terminator)) {
- // These blocks' successors have already been queued with the parent
- // color.
- continue;
- }
- for (BasicBlock *Succ : successors(Visiting)) {
- if (isa<CatchEndPadInst>(Succ->getFirstNonPHI())) {
- // The catchendpad needs to be visited with the parent's color, not
- // the current color. This will happen in the code above that visits
- // any catchpad unwind successor with the parent color, so we can
- // safely skip this successor here.
- continue;
- }
- if (BlockColors[Succ].insert(Color)) {
- DEBUG_WITH_TYPE("winehprepare-coloring",
- dbgs() << " Assigned color \'" << Color->getName()
- << "\' to block \'" << Succ->getName()
- << "\'.\n");
- Worklist.push_back({Succ, Color});
- }
- }
- }
-}
-
-static BasicBlock *getEndPadForCatch(CatchPadInst *Catch) {
- // The catch may have sibling catches. Follow the unwind chain until we get
- // to the catchendpad.
- BasicBlock *NextUnwindDest = Catch->getUnwindDest();
- auto *UnwindTerminator = NextUnwindDest->getTerminator();
- while (auto *NextCatch = dyn_cast<CatchPadInst>(UnwindTerminator)) {
- NextUnwindDest = NextCatch->getUnwindDest();
- UnwindTerminator = NextUnwindDest->getTerminator();
- }
- // The last catch in the chain must unwind to a catchendpad.
- assert(isa<CatchEndPadInst>(UnwindTerminator));
- return NextUnwindDest;
-}
-
-static void updateClonedEHPadUnwindToParent(
- BasicBlock *UnwindDest, BasicBlock *OrigBlock, BasicBlock *CloneBlock,
- std::vector<BasicBlock *> &OrigParents, BasicBlock *CloneParent) {
- auto updateUnwindTerminator = [](BasicBlock *BB) {
- auto *Terminator = BB->getTerminator();
- if (isa<CatchEndPadInst>(Terminator) ||
- isa<CleanupEndPadInst>(Terminator)) {
- removeUnwindEdge(BB);
- } else {
- // If the block we're updating has a cleanupendpad or cleanupret
- // terminator, we just want to replace that terminator with an
- // unreachable instruction.
- assert(isa<CleanupEndPadInst>(Terminator) ||
- isa<CleanupReturnInst>(Terminator));
- // Loop over all of the successors, removing the block's entry from any
- // PHI nodes.
- for (succ_iterator SI = succ_begin(BB), SE = succ_end(BB); SI != SE; ++SI)
- (*SI)->removePredecessor(BB);
- // Remove the terminator and replace it with an unreachable instruction.
- BB->getTerminator()->eraseFromParent();
- new UnreachableInst(BB->getContext(), BB);
- }
- };
-
- assert(UnwindDest->isEHPad());
- // There are many places to which this EH terminator can unwind and each has
- // slightly different rules for whether or not it fits with the given
- // location.
- auto *EHPadInst = UnwindDest->getFirstNonPHI();
- if (isa<CatchEndPadInst>(EHPadInst)) {
- auto *CloneParentCatch =
- dyn_cast<CatchPadInst>(CloneParent->getFirstNonPHI());
- if (!CloneParentCatch ||
- getEndPadForCatch(CloneParentCatch) != UnwindDest) {
- DEBUG_WITH_TYPE(
- "winehprepare-coloring",
- dbgs() << " removing unwind destination of clone block \'"
- << CloneBlock->getName() << "\'.\n");
- updateUnwindTerminator(CloneBlock);
- }
- // It's possible that the catch end pad is a legal match for both the clone
- // and the original, so they must be checked separately. If the original
- // funclet will still have multiple parents after the current clone parent
- // is removed, we'll leave its unwind terminator until later.
- assert(OrigParents.size() >= 2);
- if (OrigParents.size() != 2)
- return;
-
- // If the original funclet will have a single parent after the clone parent
- // is removed, check that parent's unwind destination.
- assert(OrigParents.front() == CloneParent ||
- OrigParents.back() == CloneParent);
- BasicBlock *OrigParent;
- if (OrigParents.front() == CloneParent)
- OrigParent = OrigParents.back();
- else
- OrigParent = OrigParents.front();
-
- auto *OrigParentCatch =
- dyn_cast<CatchPadInst>(OrigParent->getFirstNonPHI());
- if (!OrigParentCatch || getEndPadForCatch(OrigParentCatch) != UnwindDest) {
- DEBUG_WITH_TYPE(
- "winehprepare-coloring",
- dbgs() << " removing unwind destination of original block \'"
- << OrigBlock << "\'.\n");
- updateUnwindTerminator(OrigBlock);
- }
- } else if (auto *CleanupEnd = dyn_cast<CleanupEndPadInst>(EHPadInst)) {
- // If the EH terminator unwinds to a cleanupendpad, that cleanupendpad
- // must be ending a cleanuppad of either our clone parent or one
- // one of the parents of the original funclet.
- auto *CloneParentCP =
- dyn_cast<CleanupPadInst>(CloneParent->getFirstNonPHI());
- auto *EndedCP = CleanupEnd->getCleanupPad();
- if (EndedCP == CloneParentCP) {
- // If it is ending the cleanuppad of our cloned parent, then we
- // want to remove the unwind destination of the EH terminator that
- // we associated with the original funclet.
- assert(isa<CatchEndPadInst>(OrigBlock->getFirstNonPHI()));
- DEBUG_WITH_TYPE(
- "winehprepare-coloring",
- dbgs() << " removing unwind destination of original block \'"
- << OrigBlock->getName() << "\'.\n");
- updateUnwindTerminator(OrigBlock);
- } else {
- // If it isn't ending the cleanuppad of our clone parent, then we
- // want to remove the unwind destination of the EH terminator that
- // associated with our cloned funclet.
- assert(isa<CatchEndPadInst>(CloneBlock->getFirstNonPHI()));
- DEBUG_WITH_TYPE(
- "winehprepare-coloring",
- dbgs() << " removing unwind destination of clone block \'"
- << CloneBlock->getName() << "\'.\n");
- updateUnwindTerminator(CloneBlock);
- }
- } else {
- // If the EH terminator unwinds to a catchpad, cleanuppad or
- // terminatepad that EH pad must be a sibling of the funclet we're
- // cloning. We'll clone it later and update one of the catchendpad
- // instrunctions that unwinds to it at that time.
- assert(isa<CatchPadInst>(EHPadInst) || isa<CleanupPadInst>(EHPadInst) ||
- isa<TerminatePadInst>(EHPadInst));
- }
-}
-
-// If the terminator is a catchpad, we must also clone the catchendpad to which
-// it unwinds and add this to the clone parent's block list. The catchendpad
-// unwinds to either its caller, a sibling EH pad, a cleanup end pad in its
-// parent funclet or a catch end pad in its grandparent funclet (which must be
-// coupled with the parent funclet). If it has no unwind destination
-// (i.e. unwind to caller), there is nothing to be done. If the unwind
-// destination is a sibling EH pad, we will update the terminators later (in
-// resolveFuncletAncestryForPath). If it unwinds to a cleanup end pad or a
-// catch end pad and this end pad corresponds to the clone parent, we will
-// remove the unwind destination in the original catchendpad. If it unwinds to
-// a cleanup end pad or a catch end pad that does not correspond to the clone
-// parent, we will remove the unwind destination in the cloned catchendpad.
-static void updateCatchTerminators(
- Function &F, CatchPadInst *OrigCatch, CatchPadInst *CloneCatch,
- std::vector<BasicBlock *> &OrigParents, BasicBlock *CloneParent,
- ValueToValueMapTy &VMap,
- std::map<BasicBlock *, SetVector<BasicBlock *>> &BlockColors,
- std::map<BasicBlock *, std::set<BasicBlock *>> &FuncletBlocks) {
- // If we're cloning a catch pad that unwinds to a catchendpad, we also
- // need to clone the catchendpad. The coloring algorithm associates
- // the catchendpad block with the funclet's parent, so we have some work
- // to do here to figure out whether the original belongs to the clone
- // parent or one of the original funclets other parents (it might have
- // more than one at this point). In either case, we might also need to
- // remove the unwind edge if the catchendpad doesn't unwind to a block
- // in the right grandparent funclet.
- Instruction *I = CloneCatch->getUnwindDest()->getFirstNonPHI();
- if (auto *CEP = dyn_cast<CatchEndPadInst>(I)) {
- assert(BlockColors[CEP->getParent()].size() == 1);
- BasicBlock *CEPFunclet = *(BlockColors[CEP->getParent()].begin());
- BasicBlock *CEPCloneParent = nullptr;
- CatchPadInst *PredCatch = nullptr;
- if (CEPFunclet == CloneParent) {
- // The catchendpad is in the clone parent, so we need to clone it
- // and associate the clone with the original funclet's parent. If
- // the original funclet had multiple parents, we'll add it to the
- // first parent that isn't the clone parent. The logic in
- // updateClonedEHPadUnwindToParent() will only remove the unwind edge
- // if there is only one parent other than the clone parent, so we don't
- // need to verify the ancestry. The catchendpad will eventually be
- // cloned into the correct parent and all invalid unwind edges will be
- // removed.
- for (auto *Parent : OrigParents) {
- if (Parent != CloneParent) {
- CEPCloneParent = Parent;
- break;
- }
- }
- PredCatch = OrigCatch;
- } else {
- CEPCloneParent = CloneParent;
- PredCatch = CloneCatch;
- }
- assert(CEPCloneParent && PredCatch);
- DEBUG_WITH_TYPE("winehprepare-coloring",
- dbgs() << " Cloning catchendpad \'"
- << CEP->getParent()->getName() << "\' for funclet \'"
- << CEPCloneParent->getName() << "\'.\n");
- BasicBlock *ClonedCEP = CloneBasicBlock(
- CEP->getParent(), VMap, Twine(".from.", CEPCloneParent->getName()));
- // Insert the clone immediately after the original to ensure determinism
- // and to keep the same relative ordering of any funclet's blocks.
- ClonedCEP->insertInto(&F, CEP->getParent()->getNextNode());
- PredCatch->setUnwindDest(ClonedCEP);
- FuncletBlocks[CEPCloneParent].insert(ClonedCEP);
- BlockColors[ClonedCEP].insert(CEPCloneParent);
- DEBUG_WITH_TYPE("winehprepare-coloring",
- dbgs() << " Assigning color \'"
- << CEPCloneParent->getName() << "\' to block \'"
- << ClonedCEP->getName() << "\'.\n");
- auto *ClonedCEPInst = cast<CatchEndPadInst>(ClonedCEP->getTerminator());
- if (auto *Dest = ClonedCEPInst->getUnwindDest())
- updateClonedEHPadUnwindToParent(Dest, OrigCatch->getUnwindDest(),
- CloneCatch->getUnwindDest(), OrigParents,
- CloneParent);
- }
-}
-
-// While we are cloning a funclet because it has multiple parents, we will call
-// this routine to update the terminators for the original and cloned copies
-// of each basic block. All blocks in the funclet have been clone by this time.
-// OrigBlock and CloneBlock will be identical except for their block label.
-//
-// If the terminator is a catchpad, we must also clone the catchendpad to which
-// it unwinds and in most cases update either the original catchendpad or the
-// clone. See the updateCatchTerminators() helper routine for details.
-//
-// If the terminator is a catchret its successor is a block in its parent
-// funclet. If the instruction returns to a block in the parent for which the
-// cloned funclet was created, the terminator in the original block must be
-// replaced by an unreachable instruction. Otherwise the terminator in the
-// clone block must be replaced by an unreachable instruction.
-//
-// If the terminator is a cleanupret or cleanupendpad it either unwinds to
-// caller or unwinds to a sibling EH pad, a cleanup end pad in its parent
-// funclet or a catch end pad in its grandparent funclet (which must be
-// coupled with the parent funclet). If it unwinds to caller there is
-// nothing to be done. If the unwind destination is a sibling EH pad, we will
-// update the terminators later (in resolveFuncletAncestryForPath). If it
-// unwinds to a cleanup end pad or a catch end pad and this end pad corresponds
-// to the clone parent, we will replace the terminator in the original block
-// with an unreachable instruction. If it unwinds to a cleanup end pad or a
-// catch end pad that does not correspond to the clone parent, we will replace
-// the terminator in the clone block with an unreachable instruction.
-//
-// If the terminator is an invoke instruction, we will handle it after all
-// siblings of the current funclet have been cloned.
-void WinEHPrepare::updateTerminatorsAfterFuncletClone(
- Function &F, BasicBlock *OrigFunclet, BasicBlock *CloneFunclet,
- BasicBlock *OrigBlock, BasicBlock *CloneBlock, BasicBlock *CloneParent,
- ValueToValueMapTy &VMap, std::map<BasicBlock *, BasicBlock *> &Orig2Clone) {
- // If the cloned block doesn't have an exceptional terminator, there is
- // nothing to be done here.
- TerminatorInst *CloneTerminator = CloneBlock->getTerminator();
- if (!CloneTerminator->isExceptional())
- return;
-
- if (auto *CloneCatch = dyn_cast<CatchPadInst>(CloneTerminator)) {
- // A cloned catch pad has a lot of wrinkles, so we'll call a helper function
- // to update this case.
- auto *OrigCatch = cast<CatchPadInst>(OrigBlock->getTerminator());
- updateCatchTerminators(F, OrigCatch, CloneCatch,
- FuncletParents[OrigFunclet], CloneParent, VMap,
- BlockColors, FuncletBlocks);
- } else if (auto *CRI = dyn_cast<CatchReturnInst>(CloneTerminator)) {
- if (FuncletBlocks[CloneParent].count(CRI->getSuccessor())) {
- BasicBlock *OrigParent;
- // The original funclet may have more than two parents, but that's OK.
- // We just need to remap the original catchret to any of the parents.
- // All of the parents should have an entry in the EstrangedBlocks map
- // if any of them do.
- if (FuncletParents[OrigFunclet].front() == CloneParent)
- OrigParent = FuncletParents[OrigFunclet].back();
- else
- OrigParent = FuncletParents[OrigFunclet].front();
- for (succ_iterator SI = succ_begin(OrigBlock), SE = succ_end(OrigBlock);
- SI != SE; ++SI)
- (*SI)->removePredecessor(OrigBlock);
- BasicBlock *LostBlock = EstrangedBlocks[OrigParent][CRI->getSuccessor()];
- auto *OrigCatchRet = cast<CatchReturnInst>(OrigBlock->getTerminator());
- if (LostBlock) {
- OrigCatchRet->setSuccessor(LostBlock);
- } else {
- OrigCatchRet->eraseFromParent();
- new UnreachableInst(OrigBlock->getContext(), OrigBlock);
- }
- } else {
- for (succ_iterator SI = succ_begin(CloneBlock), SE = succ_end(CloneBlock);
- SI != SE; ++SI)
- (*SI)->removePredecessor(CloneBlock);
- BasicBlock *LostBlock = EstrangedBlocks[CloneParent][CRI->getSuccessor()];
- if (LostBlock) {
- CRI->setSuccessor(LostBlock);
- } else {
- CRI->eraseFromParent();
- new UnreachableInst(CloneBlock->getContext(), CloneBlock);
- }
- }
- } else if (isa<CleanupReturnInst>(CloneTerminator) ||
- isa<CleanupEndPadInst>(CloneTerminator)) {
- BasicBlock *UnwindDest = nullptr;
-
- // A cleanup pad can unwind through either a cleanupret or a cleanupendpad
- // but both are handled the same way.
- if (auto *CRI = dyn_cast<CleanupReturnInst>(CloneTerminator))
- UnwindDest = CRI->getUnwindDest();
- else if (auto *CEI = dyn_cast<CleanupEndPadInst>(CloneTerminator))
- UnwindDest = CEI->getUnwindDest();
-
- // If the instruction has no local unwind destination, there is nothing
- // to be done.
- if (!UnwindDest)
- return;
-
- // The unwind destination may be a sibling EH pad, a catchendpad in
- // a grandparent funclet (ending a catchpad in the parent) or a cleanup
- // cleanupendpad in the parent. Call a helper routine to diagnose this
- // and remove either the clone or original terminator as needed.
- updateClonedEHPadUnwindToParent(UnwindDest, OrigBlock, CloneBlock,
- FuncletParents[OrigFunclet], CloneParent);
- }
-}
-
-// Clones all blocks used by the specified funclet to avoid the funclet having
-// multiple parent funclets. All terminators in the parent that unwind to the
-// original funclet are remapped to unwind to the clone. Any terminator in the
-// original funclet which returned to this parent is converted to an unreachable
-// instruction. Likewise, any terminator in the cloned funclet which returns to
-// a parent funclet other than the specified parent is converted to an
-// unreachable instruction.
-BasicBlock *WinEHPrepare::cloneFuncletForParent(Function &F,
- BasicBlock *FuncletEntry,
- BasicBlock *Parent) {
- std::set<BasicBlock *> &BlocksInFunclet = FuncletBlocks[FuncletEntry];
-
- DEBUG_WITH_TYPE("winehprepare-coloring",
- dbgs() << "Cloning funclet \'" << FuncletEntry->getName()
- << "\' for parent \'" << Parent->getName() << "\'.\n");
-
- std::map<BasicBlock *, BasicBlock *> Orig2Clone;
- ValueToValueMapTy VMap;
- for (BasicBlock *BB : BlocksInFunclet) {
- // Create a new basic block and copy instructions into it.
- BasicBlock *CBB =
- CloneBasicBlock(BB, VMap, Twine(".from.", Parent->getName()));
-
- // Insert the clone immediately after the original to ensure determinism
- // and to keep the same relative ordering of any funclet's blocks.
- CBB->insertInto(&F, BB->getNextNode());
-
- // Add basic block mapping.
- VMap[BB] = CBB;
-
- // Record delta operations that we need to perform to our color mappings.
- Orig2Clone[BB] = CBB;
- } // end for (BasicBlock *BB : BlocksInFunclet)
-
- BasicBlock *ClonedFunclet = Orig2Clone[FuncletEntry];
- assert(ClonedFunclet);
-
- // Set the coloring for the blocks we just cloned.
- std::set<BasicBlock *> &ClonedBlocks = FuncletBlocks[ClonedFunclet];
- for (auto &BBMapping : Orig2Clone) {
- BasicBlock *NewBlock = BBMapping.second;
- ClonedBlocks.insert(NewBlock);
- BlockColors[NewBlock].insert(ClonedFunclet);
-
- DEBUG_WITH_TYPE("winehprepare-coloring",
- dbgs() << " Assigning color \'" << ClonedFunclet->getName()
- << "\' to block \'" << NewBlock->getName()
- << "\'.\n");
-
- // Use the VMap to remap the instructions in this cloned block.
- for (Instruction &I : *NewBlock)
- RemapInstruction(&I, VMap, RF_IgnoreMissingEntries);
- }
-
- // All the cloned blocks have to be colored in the loop above before we can
- // update the terminators because doing so can require checking the color of
- // other blocks in the cloned funclet.
- for (auto &BBMapping : Orig2Clone) {
- BasicBlock *OldBlock = BBMapping.first;
- BasicBlock *NewBlock = BBMapping.second;
-
- // Update the terminator, if necessary, in both the original block and the
- // cloned so that the original funclet never returns to a block in the
- // clone parent and the clone funclet never returns to a block in any other
- // of the original funclet's parents.
- updateTerminatorsAfterFuncletClone(F, FuncletEntry, ClonedFunclet, OldBlock,
- NewBlock, Parent, VMap, Orig2Clone);
-
- // Check to see if the cloned block successor has PHI nodes. If so, we need
- // to add entries to the PHI nodes for the cloned block now.
- for (BasicBlock *SuccBB : successors(NewBlock)) {
- for (Instruction &SuccI : *SuccBB) {
- auto *SuccPN = dyn_cast<PHINode>(&SuccI);
- if (!SuccPN)
- break;
-
- // Ok, we have a PHI node. Figure out what the incoming value was for
- // the OldBlock.
- int OldBlockIdx = SuccPN->getBasicBlockIndex(OldBlock);
- if (OldBlockIdx == -1)
- break;
- Value *IV = SuccPN->getIncomingValue(OldBlockIdx);
-
- // Remap the value if necessary.
- if (auto *Inst = dyn_cast<Instruction>(IV)) {
- ValueToValueMapTy::iterator I = VMap.find(Inst);
- if (I != VMap.end())
- IV = I->second;
- }
+void WinEHPrepare::colorFunclets(Function &F) {
+ BlockColors = colorEHFunclets(F);
- SuccPN->addIncoming(IV, NewBlock);
- }
- }
- }
-
- // Erase the clone's parent from the original funclet's parent list.
- std::vector<BasicBlock *> &Parents = FuncletParents[FuncletEntry];
- Parents.erase(std::remove(Parents.begin(), Parents.end(), Parent),
- Parents.end());
-
- // Store the cloned funclet's parent.
- assert(std::find(FuncletParents[ClonedFunclet].begin(),
- FuncletParents[ClonedFunclet].end(),
- Parent) == std::end(FuncletParents[ClonedFunclet]));
- FuncletParents[ClonedFunclet].push_back(Parent);
-
- // Copy any children of the original funclet to the clone. We'll either
- // clone them too or make that path unreachable when we take the next step
- // in resolveFuncletAncestryForPath().
- for (auto *Child : FuncletChildren[FuncletEntry]) {
- assert(std::find(FuncletChildren[ClonedFunclet].begin(),
- FuncletChildren[ClonedFunclet].end(),
- Child) == std::end(FuncletChildren[ClonedFunclet]));
- FuncletChildren[ClonedFunclet].push_back(Child);
- assert(std::find(FuncletParents[Child].begin(), FuncletParents[Child].end(),
- ClonedFunclet) == std::end(FuncletParents[Child]));
- FuncletParents[Child].push_back(ClonedFunclet);
- }
-
- // Find any blocks that unwound to the original funclet entry from the
- // clone parent block and remap them to the clone.
- for (auto *U : FuncletEntry->users()) {
- auto *UT = dyn_cast<TerminatorInst>(U);
- if (!UT)
- continue;
- BasicBlock *UBB = UT->getParent();
- assert(BlockColors[UBB].size() == 1);
- BasicBlock *UFunclet = *(BlockColors[UBB].begin());
- // Funclets shouldn't be able to loop back on themselves.
- assert(UFunclet != FuncletEntry);
- // If this instruction unwinds to the original funclet from the clone
- // parent, remap the terminator so that it unwinds to the clone instead.
- // We will perform a similar transformation for siblings after all
- // the siblings have been cloned.
- if (UFunclet == Parent) {
- // We're about to break the path from this block to the uncloned funclet
- // entry, so remove it as a predeccessor to clean up the PHIs.
- FuncletEntry->removePredecessor(UBB);
- TerminatorInst *Terminator = UBB->getTerminator();
- RemapInstruction(Terminator, VMap, RF_IgnoreMissingEntries);
- }
- }
-
- // This asserts a condition that is relied upon inside the loop below,
- // namely that no predecessors of the original funclet entry block
- // are also predecessors of the cloned funclet entry block.
- assert(std::all_of(pred_begin(FuncletEntry), pred_end(FuncletEntry),
- [&ClonedFunclet](BasicBlock *Pred) {
- return std::find(pred_begin(ClonedFunclet),
- pred_end(ClonedFunclet),
- Pred) == pred_end(ClonedFunclet);
- }));
-
- // Remove any invalid PHI node entries in the cloned funclet.cl
- std::vector<PHINode *> PHIsToErase;
- for (Instruction &I : *ClonedFunclet) {
- auto *PN = dyn_cast<PHINode>(&I);
- if (!PN)
- break;
-
- // Predecessors of the original funclet do not reach the cloned funclet,
- // but the cloning process assumes they will. Remove them now.
- for (auto *Pred : predecessors(FuncletEntry))
- PN->removeIncomingValue(Pred, false);
- }
- for (auto *PN : PHIsToErase)
- PN->eraseFromParent();
-
- // Replace the original funclet in the parent's children vector with the
- // cloned funclet.
- for (auto &It : FuncletChildren[Parent]) {
- if (It == FuncletEntry) {
- It = ClonedFunclet;
- break;
- }
- }
-
- return ClonedFunclet;
-}
-
-// Removes the unwind edge for any exceptional terminators within the specified
-// parent funclet that previously unwound to the specified child funclet.
-void WinEHPrepare::makeFuncletEdgeUnreachable(BasicBlock *Parent,
- BasicBlock *Child) {
- for (BasicBlock *BB : FuncletBlocks[Parent]) {
- TerminatorInst *Terminator = BB->getTerminator();
- if (!Terminator->isExceptional())
- continue;
-
- // Look for terninators that unwind to the child funclet.
- BasicBlock *UnwindDest = nullptr;
- if (auto *I = dyn_cast<InvokeInst>(Terminator))
- UnwindDest = I->getUnwindDest();
- else if (auto *I = dyn_cast<CatchEndPadInst>(Terminator))
- UnwindDest = I->getUnwindDest();
- else if (auto *I = dyn_cast<TerminatePadInst>(Terminator))
- UnwindDest = I->getUnwindDest();
- // cleanupendpad, catchret and cleanupret don't represent a parent-to-child
- // funclet transition, so we don't need to consider them here.
-
- // If the child funclet is the unwind destination, replace the terminator
- // with an unreachable instruction.
- if (UnwindDest == Child)
- removeUnwindEdge(BB);
- }
- // The specified parent is no longer a parent of the specified child.
- std::vector<BasicBlock *> &Children = FuncletChildren[Parent];
- Children.erase(std::remove(Children.begin(), Children.end(), Child),
- Children.end());
-}
-
-// This routine is called after funclets with multiple parents are cloned for
-// a specific parent. Here we look for children of the specified funclet that
-// unwind to other children of that funclet and update the unwind destinations
-// to ensure that each sibling is connected to the correct clone of the sibling
-// to which it unwinds.
-//
-// If the terminator is an invoke instruction, it unwinds either to a child
-// EH pad, a cleanup end pad in the current funclet, or a catch end pad in a
-// parent funclet (which ends either the current catch pad or a sibling
-// catch pad). If it unwinds to a child EH pad, the child will have multiple
-// parents after this funclet is cloned and this case will be handled later in
-// the resolveFuncletAncestryForPath processing. If it unwinds to a
-// cleanup end pad in the current funclet, the instruction remapping during
-// the cloning process should have already mapped the unwind destination to
-// the cloned copy of the cleanup end pad. If it unwinds to a catch end pad
-// there are two possibilities: either the catch end pad is the unwind
-// destination for the catch pad we are currently cloning or it is the unwind
-// destination for a sibling catch pad. If it it the unwind destination of the
-// catch pad we are cloning, we need to update the cloned invoke instruction
-// to unwind to the cloned catch end pad. Otherwise, we will handle this
-// later (in resolveFuncletAncestryForPath).
-static void updateSiblingToSiblingUnwind(
- BasicBlock *CurFunclet,
- std::map<BasicBlock *, SetVector<BasicBlock *>> &BlockColors,
- std::map<BasicBlock *, std::set<BasicBlock *>> &FuncletBlocks,
- std::map<BasicBlock *, std::vector<BasicBlock *>> &FuncletParents,
- std::map<BasicBlock *, std::vector<BasicBlock *>> &FuncletChildren,
- std::map<BasicBlock *, BasicBlock *> &Funclet2Orig) {
- // Remap any bad sibling-to-sibling transitions for funclets that
- // we just cloned.
- for (BasicBlock *ChildFunclet : FuncletChildren[CurFunclet]) {
- for (auto *BB : FuncletBlocks[ChildFunclet]) {
- TerminatorInst *Terminator = BB->getTerminator();
- if (!Terminator->isExceptional())
- continue;
-
- // See if this terminator has an unwind destination.
- // Note that catchendpads are handled when the associated catchpad
- // is cloned. They don't fit the pattern we're looking for here.
- BasicBlock *UnwindDest = nullptr;
- if (auto *I = dyn_cast<CatchPadInst>(Terminator)) {
- UnwindDest = I->getUnwindDest();
- // The catchendpad is not a sibling destination. This case should
- // have been handled in cloneFuncletForParent().
- if (isa<CatchEndPadInst>(Terminator)) {
- assert(BlockColors[UnwindDest].size() == 1 &&
- "Cloned catchpad unwinds to an pad with multiple parents.");
- assert(FuncletParents[UnwindDest].front() == CurFunclet &&
- "Cloned catchpad unwinds to the wrong parent.");
- continue;
- }
- } else {
- if (auto *I = dyn_cast<CleanupReturnInst>(Terminator))
- UnwindDest = I->getUnwindDest();
- else if (auto *I = dyn_cast<CleanupEndPadInst>(Terminator))
- UnwindDest = I->getUnwindDest();
-
- // If the cleanup unwinds to caller, there is nothing to be done.
- if (!UnwindDest)
- continue;
- }
-
- // If the destination is not a cleanup pad, catch pad or terminate pad
- // we don't need to handle it here.
- Instruction *EHPad = UnwindDest->getFirstNonPHI();
- if (!isa<CleanupPadInst>(EHPad) && !isa<CatchPadInst>(EHPad) &&
- !isa<TerminatePadInst>(EHPad))
- continue;
-
- // If it is one of these, then it is either a sibling of the current
- // child funclet or a clone of one of those siblings.
- // If it is a sibling, no action is needed.
- if (FuncletParents[UnwindDest].size() == 1 &&
- FuncletParents[UnwindDest].front() == CurFunclet)
- continue;
-
- // If the unwind destination is a clone of a sibling, we need to figure
- // out which sibling it is a clone of and use that sibling as the
- // unwind destination.
- BasicBlock *DestOrig = Funclet2Orig[UnwindDest];
- BasicBlock *TargetSibling = nullptr;
- for (auto &Mapping : Funclet2Orig) {
- if (Mapping.second != DestOrig)
- continue;
- BasicBlock *MappedFunclet = Mapping.first;
- if (FuncletParents[MappedFunclet].size() == 1 &&
- FuncletParents[MappedFunclet].front() == CurFunclet) {
- TargetSibling = MappedFunclet;
- }
- }
- // If we didn't find the sibling we were looking for then the
- // unwind destination is not a clone of one of child's siblings.
- // That's unexpected.
- assert(TargetSibling && "Funclet unwinds to unexpected destination.");
-
- // Update the terminator instruction to unwind to the correct sibling.
- if (auto *I = dyn_cast<CatchPadInst>(Terminator))
- I->setUnwindDest(TargetSibling);
- else if (auto *I = dyn_cast<CleanupReturnInst>(Terminator))
- I->setUnwindDest(TargetSibling);
- else if (auto *I = dyn_cast<CleanupEndPadInst>(Terminator))
- I->setUnwindDest(TargetSibling);
- }
- }
-
- // Invoke remapping can't be done correctly until after all of their
- // other sibling-to-sibling unwinds have been remapped.
- for (BasicBlock *ChildFunclet : FuncletChildren[CurFunclet]) {
- bool NeedOrigInvokeRemapping = false;
- for (auto *BB : FuncletBlocks[ChildFunclet]) {
- TerminatorInst *Terminator = BB->getTerminator();
- auto *II = dyn_cast<InvokeInst>(Terminator);
- if (!II)
- continue;
-
- BasicBlock *UnwindDest = II->getUnwindDest();
- assert(UnwindDest && "Invoke unwinds to a null destination.");
- assert(UnwindDest->isEHPad() && "Invoke does not unwind to an EH pad.");
- auto *EHPadInst = UnwindDest->getFirstNonPHI();
- if (isa<CleanupEndPadInst>(EHPadInst)) {
- // An invoke that unwinds to a cleanup end pad must be in a cleanup pad.
- assert(isa<CleanupPadInst>(ChildFunclet->getFirstNonPHI()) &&
- "Unwinding to cleanup end pad from a non cleanup pad funclet.");
- // The funclet cloning should have remapped the destination to the cloned
- // cleanup end pad.
- assert(FuncletBlocks[ChildFunclet].count(UnwindDest) &&
- "Unwind destination for invoke was not updated during cloning.");
- } else if (isa<CatchEndPadInst>(EHPadInst)) {
- // If the invoke unwind destination is the unwind destination for
- // the current child catch pad funclet, there is nothing to be done.
- BasicBlock *OrigFunclet = Funclet2Orig[ChildFunclet];
- auto *CurCatch = cast<CatchPadInst>(ChildFunclet->getFirstNonPHI());
- auto *OrigCatch = cast<CatchPadInst>(OrigFunclet->getFirstNonPHI());
- if (OrigCatch->getUnwindDest() == UnwindDest) {
- // If the invoke unwinds to a catch end pad that is the unwind
- // destination for the original catch pad, the cloned invoke should
- // unwind to the cloned catch end pad.
- II->setUnwindDest(CurCatch->getUnwindDest());
- } else if (CurCatch->getUnwindDest() == UnwindDest) {
- // If the invoke unwinds to a catch end pad that is the unwind
- // destination for the clone catch pad, the original invoke should
- // unwind to the unwind destination of the original catch pad.
- // This happens when the catch end pad is matched to the clone
- // parent when the catchpad instruction is cloned and the original
- // invoke instruction unwinds to the original catch end pad (which
- // is now the unwind destination of the cloned catch pad).
- NeedOrigInvokeRemapping = true;
- } else {
- // Otherwise, the invoke unwinds to a catch end pad that is the unwind
- // destination another catch pad in the unwind chain from either the
- // current catch pad or one of its clones. If it is already the
- // catch end pad at the end unwind chain from the current catch pad,
- // we'll need to check the invoke instructions in the original funclet
- // later. Otherwise, we need to remap this invoke now.
- assert((getEndPadForCatch(OrigCatch) == UnwindDest ||
- getEndPadForCatch(CurCatch) == UnwindDest) &&
- "Invoke within catch pad unwinds to an invalid catch end pad.");
- BasicBlock *CurCatchEnd = getEndPadForCatch(CurCatch);
- if (CurCatchEnd == UnwindDest)
- NeedOrigInvokeRemapping = true;
- else
- II->setUnwindDest(CurCatchEnd);
- }
- }
- }
- if (NeedOrigInvokeRemapping) {
- // To properly remap invoke instructions that unwind to catch end pads
- // that are not the unwind destination of the catch pad funclet in which
- // the invoke appears, we must also look at the uncloned invoke in the
- // original funclet. If we saw an invoke that was already properly
- // unwinding to a sibling's catch end pad, we need to check the invokes
- // in the original funclet.
- BasicBlock *OrigFunclet = Funclet2Orig[ChildFunclet];
- for (auto *BB : FuncletBlocks[OrigFunclet]) {
- auto *II = dyn_cast<InvokeInst>(BB->getTerminator());
- if (!II)
- continue;
-
- BasicBlock *UnwindDest = II->getUnwindDest();
- assert(UnwindDest && "Invoke unwinds to a null destination.");
- assert(UnwindDest->isEHPad() && "Invoke does not unwind to an EH pad.");
- auto *CEP = dyn_cast<CatchEndPadInst>(UnwindDest->getFirstNonPHI());
- if (!CEP)
- continue;
-
- // If the invoke unwind destination is the unwind destination for
- // the original catch pad funclet, there is nothing to be done.
- auto *OrigCatch = cast<CatchPadInst>(OrigFunclet->getFirstNonPHI());
-
- // If the invoke unwinds to a catch end pad that is neither the unwind
- // destination of OrigCatch or the destination another catch pad in the
- // unwind chain from current catch pad, we need to remap the invoke.
- BasicBlock *OrigCatchEnd = getEndPadForCatch(OrigCatch);
- if (OrigCatchEnd != UnwindDest)
- II->setUnwindDest(OrigCatchEnd);
- }
- }
- }
-}
-
-void WinEHPrepare::resolveFuncletAncestry(
- Function &F, SmallVectorImpl<BasicBlock *> &EntryBlocks) {
- // Most of the time this will be unnecessary. If the conditions arise that
- // require this work, this flag will be set.
- if (!FuncletCloningRequired)
- return;
-
- // Funclet2Orig is used to map any cloned funclets back to the original
- // funclet from which they were cloned. The map is seeded with the
- // original funclets mapping to themselves.
- std::map<BasicBlock *, BasicBlock *> Funclet2Orig;
- for (auto *Funclet : EntryBlocks)
- Funclet2Orig[Funclet] = Funclet;
-
- // Start with the entry funclet and walk the funclet parent-child tree.
- SmallVector<BasicBlock *, 4> FuncletPath;
- FuncletPath.push_back(&(F.getEntryBlock()));
- resolveFuncletAncestryForPath(F, FuncletPath, Funclet2Orig);
-}
-
-// Walks the funclet control flow, cloning any funclets that have more than one
-// parent funclet and breaking any cyclic unwind chains so that the path becomes
-// unreachable at the point where a funclet would have unwound to a funclet that
-// was already in the chain.
-void WinEHPrepare::resolveFuncletAncestryForPath(
- Function &F, SmallVectorImpl<BasicBlock *> &FuncletPath,
- std::map<BasicBlock *, BasicBlock *> &Funclet2Orig) {
- bool ClonedAnyChildren = false;
- BasicBlock *CurFunclet = FuncletPath.back();
- // Copy the children vector because we might changing it.
- std::vector<BasicBlock *> Children(FuncletChildren[CurFunclet]);
- for (BasicBlock *ChildFunclet : Children) {
- // Don't allow the funclet chain to unwind back on itself.
- // If this funclet is already in the current funclet chain, make the
- // path to it through the current funclet unreachable.
- bool IsCyclic = false;
- BasicBlock *ChildIdentity = Funclet2Orig[ChildFunclet];
- for (BasicBlock *Ancestor : FuncletPath) {
- BasicBlock *AncestorIdentity = Funclet2Orig[Ancestor];
- if (AncestorIdentity == ChildIdentity) {
- IsCyclic = true;
- break;
- }
- }
- // If the unwind chain wraps back on itself, break the chain.
- if (IsCyclic) {
- makeFuncletEdgeUnreachable(CurFunclet, ChildFunclet);
- continue;
- }
- // If this child funclet has other parents, clone the entire funclet.
- if (FuncletParents[ChildFunclet].size() > 1) {
- ChildFunclet = cloneFuncletForParent(F, ChildFunclet, CurFunclet);
- Funclet2Orig[ChildFunclet] = ChildIdentity;
- ClonedAnyChildren = true;
- }
- FuncletPath.push_back(ChildFunclet);
- resolveFuncletAncestryForPath(F, FuncletPath, Funclet2Orig);
- FuncletPath.pop_back();
- }
- // If we didn't clone any children, we can return now.
- if (!ClonedAnyChildren)
- return;
-
- updateSiblingToSiblingUnwind(CurFunclet, BlockColors, FuncletBlocks,
- FuncletParents, FuncletChildren, Funclet2Orig);
-}
-
-void WinEHPrepare::colorFunclets(Function &F,
- SmallVectorImpl<BasicBlock *> &EntryBlocks) {
- ::colorFunclets(F, EntryBlocks, BlockColors, FuncletBlocks);
-
- // The processing above actually accumulated the parent set for this
- // funclet into the color set for its entry; use the parent set to
- // populate the children map, and reset the color set to include just
- // the funclet itself (no instruction can target a funclet entry except on
- // that transitions to the child funclet).
- for (BasicBlock *FuncletEntry : EntryBlocks) {
- SetVector<BasicBlock *> &ColorMapItem = BlockColors[FuncletEntry];
- // It will be rare for funclets to have multiple parents, but if any
- // do we need to clone the funclet later to address that. Here we
- // set a flag indicating that this case has arisen so that we don't
- // have to do a lot of checking later to handle the more common case.
- if (ColorMapItem.size() > 1)
- FuncletCloningRequired = true;
- for (BasicBlock *Parent : ColorMapItem) {
- assert(std::find(FuncletChildren[Parent].begin(),
- FuncletChildren[Parent].end(),
- FuncletEntry) == std::end(FuncletChildren[Parent]));
- FuncletChildren[Parent].push_back(FuncletEntry);
- assert(std::find(FuncletParents[FuncletEntry].begin(),
- FuncletParents[FuncletEntry].end(),
- Parent) == std::end(FuncletParents[FuncletEntry]));
- FuncletParents[FuncletEntry].push_back(Parent);
- }
- ColorMapItem.clear();
- ColorMapItem.insert(FuncletEntry);
+ // Invert the map from BB to colors to color to BBs.
+ for (BasicBlock &BB : F) {
+ ColorVector &Colors = BlockColors[&BB];
+ for (BasicBlock *Color : Colors)
+ FuncletBlocks[Color].push_back(&BB);
}
}
void llvm::calculateCatchReturnSuccessorColors(const Function *Fn,
WinEHFuncInfo &FuncInfo) {
- SmallVector<BasicBlock *, 4> EntryBlocks;
- // colorFunclets needs the set of EntryBlocks, get them using
- // findFuncletEntryPoints.
- findFuncletEntryPoints(const_cast<Function &>(*Fn), EntryBlocks);
-
- std::map<BasicBlock *, SetVector<BasicBlock *>> BlockColors;
- std::map<BasicBlock *, std::set<BasicBlock *>> FuncletBlocks;
- // Figure out which basic blocks belong to which funclets.
- colorFunclets(const_cast<Function &>(*Fn), EntryBlocks, BlockColors,
- FuncletBlocks);
-
- // The static colorFunclets routine assigns multiple colors to funclet entries
- // because that information is needed to calculate funclets' parent-child
- // relationship, but we don't need those relationship here and ultimately the
- // entry blocks should have the color of the funclet they begin.
- for (BasicBlock *FuncletEntry : EntryBlocks) {
- BlockColors[FuncletEntry].clear();
- BlockColors[FuncletEntry].insert(FuncletEntry);
- }
-
- // We need to find the catchret successors. To do this, we must first find
- // all the catchpad funclets.
- for (auto &Funclet : FuncletBlocks) {
- // Figure out what kind of funclet we are looking at; We only care about
- // catchpads.
- BasicBlock *FuncletPadBB = Funclet.first;
- Instruction *FirstNonPHI = FuncletPadBB->getFirstNonPHI();
- auto *CatchPad = dyn_cast<CatchPadInst>(FirstNonPHI);
- if (!CatchPad)
+ for (const BasicBlock &BB : *Fn) {
+ const auto *CatchRet = dyn_cast<CatchReturnInst>(BB.getTerminator());
+ if (!CatchRet)
continue;
-
- // The users of a catchpad are always catchrets.
- for (User *Exit : CatchPad->users()) {
- auto *CatchReturn = dyn_cast<CatchReturnInst>(Exit);
- if (!CatchReturn)
- continue;
- BasicBlock *CatchRetSuccessor = CatchReturn->getSuccessor();
- SetVector<BasicBlock *> &SuccessorColors = BlockColors[CatchRetSuccessor];
- assert(SuccessorColors.size() == 1 && "Expected BB to be monochrome!");
- BasicBlock *Color = *SuccessorColors.begin();
- // Record the catchret successor's funclet membership.
- FuncInfo.CatchRetSuccessorColorMap[CatchReturn] = Color;
- }
+ // A 'catchret' returns to the outer scope's color.
+ Value *ParentPad = CatchRet->getParentPad();
+ const BasicBlock *Color;
+ if (isa<ConstantTokenNone>(ParentPad))
+ Color = &Fn->getEntryBlock();
+ else
+ Color = cast<Instruction>(ParentPad)->getParent();
+ // Record the catchret successor's funclet membership.
+ FuncInfo.CatchRetSuccessorColorMap[CatchRet] = Color;
}
}
@@ -1584,70 +620,23 @@ void WinEHPrepare::demotePHIsOnFunclets(Function &F) {
}
}
-void WinEHPrepare::cloneCommonBlocks(
- Function &F, SmallVectorImpl<BasicBlock *> &EntryBlocks) {
+void WinEHPrepare::cloneCommonBlocks(Function &F) {
// We need to clone all blocks which belong to multiple funclets. Values are
// remapped throughout the funclet to propogate both the new instructions
// *and* the new basic blocks themselves.
- for (BasicBlock *FuncletPadBB : EntryBlocks) {
- std::set<BasicBlock *> &BlocksInFunclet = FuncletBlocks[FuncletPadBB];
+ for (auto &Funclets : FuncletBlocks) {
+ BasicBlock *FuncletPadBB = Funclets.first;
+ std::vector<BasicBlock *> &BlocksInFunclet = Funclets.second;
- std::map<BasicBlock *, BasicBlock *> Orig2Clone;
+ std::vector<std::pair<BasicBlock *, BasicBlock *>> Orig2Clone;
ValueToValueMapTy VMap;
- for (auto BlockIt = BlocksInFunclet.begin(),
- BlockEnd = BlocksInFunclet.end();
- BlockIt != BlockEnd;) {
- // Increment the iterator inside the loop because we might be removing
- // blocks from the set.
- BasicBlock *BB = *BlockIt++;
- SetVector<BasicBlock *> &ColorsForBB = BlockColors[BB];
+ for (BasicBlock *BB : BlocksInFunclet) {
+ ColorVector &ColorsForBB = BlockColors[BB];
// We don't need to do anything if the block is monochromatic.
size_t NumColorsForBB = ColorsForBB.size();
if (NumColorsForBB == 1)
continue;
- // If this block is a catchendpad, it shouldn't be cloned.
- // We will only see a catchendpad with multiple colors in the case where
- // some funclet has multiple parents. In that case, the color will be
- // resolved during the resolveFuncletAncestry processing.
- // For now, find the catchpad that unwinds to this block and assign
- // that catchpad's first parent to be the color for this block.
- if (isa<CatchEndPadInst>(BB->getFirstNonPHI())) {
- assert(
- FuncletCloningRequired &&
- "Found multi-colored catchendpad with no multi-parent funclets.");
- BasicBlock *CatchParent = nullptr;
- // There can only be one catchpad predecessor for a catchendpad.
- for (BasicBlock *PredBB : predecessors(BB)) {
- if (isa<CatchPadInst>(PredBB->getTerminator())) {
- CatchParent = PredBB;
- break;
- }
- }
- // There must be one catchpad predecessor for a catchendpad.
- assert(CatchParent && "No catchpad found for catchendpad.");
-
- // If the catchpad has multiple parents, we'll clone the catchendpad
- // when we clone the catchpad funclet and insert it into the correct
- // funclet. For now, we just select the first parent of the catchpad
- // and give the catchendpad that color.
- BasicBlock *CorrectColor = FuncletParents[CatchParent].front();
- assert(FuncletBlocks[CorrectColor].count(BB));
- assert(BlockColors[BB].count(CorrectColor));
-
- // Remove this block from the FuncletBlocks set of any funclet that
- // isn't the funclet whose color we just selected.
- for (BasicBlock *ContainingFunclet : BlockColors[BB])
- if (ContainingFunclet != CorrectColor)
- FuncletBlocks[ContainingFunclet].erase(BB);
- BlockColors[BB].remove_if([&](BasicBlock *ContainingFunclet) {
- return ContainingFunclet != CorrectColor;
- });
- // This should leave just one color for BB.
- assert(BlockColors[BB].size() == 1);
- continue;
- }
-
DEBUG_WITH_TYPE("winehprepare-coloring",
dbgs() << " Cloning block \'" << BB->getName()
<< "\' for funclet \'" << FuncletPadBB->getName()
@@ -1664,7 +653,7 @@ void WinEHPrepare::cloneCommonBlocks(
VMap[BB] = CBB;
// Record delta operations that we need to perform to our color mappings.
- Orig2Clone[BB] = CBB;
+ Orig2Clone.emplace_back(BB, CBB);
}
// If nothing was cloned, we're done cloning in this funclet.
@@ -1677,55 +666,28 @@ void WinEHPrepare::cloneCommonBlocks(
BasicBlock *OldBlock = BBMapping.first;
BasicBlock *NewBlock = BBMapping.second;
- BlocksInFunclet.insert(NewBlock);
- BlockColors[NewBlock].insert(FuncletPadBB);
+ BlocksInFunclet.push_back(NewBlock);
+ ColorVector &NewColors = BlockColors[NewBlock];
+ assert(NewColors.empty() && "A new block should only have one color!");
+ NewColors.push_back(FuncletPadBB);
DEBUG_WITH_TYPE("winehprepare-coloring",
dbgs() << " Assigned color \'" << FuncletPadBB->getName()
<< "\' to block \'" << NewBlock->getName()
<< "\'.\n");
- BlocksInFunclet.erase(OldBlock);
- BlockColors[OldBlock].remove(FuncletPadBB);
+ BlocksInFunclet.erase(
+ std::remove(BlocksInFunclet.begin(), BlocksInFunclet.end(), OldBlock),
+ BlocksInFunclet.end());
+ ColorVector &OldColors = BlockColors[OldBlock];
+ OldColors.erase(
+ std::remove(OldColors.begin(), OldColors.end(), FuncletPadBB),
+ OldColors.end());
DEBUG_WITH_TYPE("winehprepare-coloring",
dbgs() << " Removed color \'" << FuncletPadBB->getName()
<< "\' from block \'" << OldBlock->getName()
<< "\'.\n");
-
- // If we are cloning a funclet that might share a child funclet with
- // another funclet, look to see if the cloned block is reached from a
- // catchret instruction. If so, save this association so we can retrieve
- // the possibly orphaned clone when we clone the child funclet.
- if (FuncletCloningRequired) {
- for (auto *Pred : predecessors(OldBlock)) {
- auto *Terminator = Pred->getTerminator();
- if (!isa<CatchReturnInst>(Terminator))
- continue;
- // If this block is reached from a catchret instruction in a funclet
- // that has multiple parents, it will have a color for each of those
- // parents. We just removed the color of one of the parents, but
- // the cloned block will be unreachable until we clone the child
- // funclet that contains the catchret instruction. In that case we
- // need to create a mapping that will let us find the cloned block
- // later and associate it with the cloned child funclet.
- bool BlockWillBeEstranged = false;
- for (auto *Color : BlockColors[Pred]) {
- if (FuncletParents[Color].size() > 1) {
- BlockWillBeEstranged = true;
- break; // Breaks out of the color loop
- }
- }
- if (BlockWillBeEstranged) {
- EstrangedBlocks[FuncletPadBB][OldBlock] = NewBlock;
- DEBUG_WITH_TYPE("winehprepare-coloring",
- dbgs() << " Saved mapping of estranged block \'"
- << NewBlock->getName() << "\' for \'"
- << FuncletPadBB->getName() << "\'.\n");
- break; // Breaks out of the predecessor loop
- }
- }
- }
}
// Loop over all of the instructions in this funclet, fixing up operand
@@ -1736,6 +698,40 @@ void WinEHPrepare::cloneCommonBlocks(
RemapInstruction(&I, VMap,
RF_IgnoreMissingEntries | RF_NoModuleLevelChanges);
+ auto UpdatePHIOnClonedBlock = [&](PHINode *PN, bool IsForOldBlock) {
+ unsigned NumPreds = PN->getNumIncomingValues();
+ for (unsigned PredIdx = 0, PredEnd = NumPreds; PredIdx != PredEnd;
+ ++PredIdx) {
+ BasicBlock *IncomingBlock = PN->getIncomingBlock(PredIdx);
+ ColorVector &IncomingColors = BlockColors[IncomingBlock];
+ bool BlockInFunclet = IncomingColors.size() == 1 &&
+ IncomingColors.front() == FuncletPadBB;
+ if (IsForOldBlock != BlockInFunclet)
+ continue;
+ PN->removeIncomingValue(IncomingBlock, /*DeletePHIIfEmpty=*/false);
+ // Revisit the next entry.
+ --PredIdx;
+ --PredEnd;
+ }
+ };
+
+ for (auto &BBMapping : Orig2Clone) {
+ BasicBlock *OldBlock = BBMapping.first;
+ BasicBlock *NewBlock = BBMapping.second;
+ for (Instruction &OldI : *OldBlock) {
+ auto *OldPN = dyn_cast<PHINode>(&OldI);
+ if (!OldPN)
+ break;
+ UpdatePHIOnClonedBlock(OldPN, /*IsForOldBlock=*/true);
+ }
+ for (Instruction &NewI : *NewBlock) {
+ auto *NewPN = dyn_cast<PHINode>(&NewI);
+ if (!NewPN)
+ break;
+ UpdatePHIOnClonedBlock(NewPN, /*IsForOldBlock=*/false);
+ }
+ }
+
// Check to see if SuccBB has PHI nodes. If so, we need to add entries to
// the PHI nodes for NewBB now.
for (auto &BBMapping : Orig2Clone) {
@@ -1783,7 +779,7 @@ void WinEHPrepare::cloneCommonBlocks(
for (Use &U : OldI->uses()) {
Instruction *UserI = cast<Instruction>(U.getUser());
BasicBlock *UserBB = UserI->getParent();
- SetVector<BasicBlock *> &ColorsForUserBB = BlockColors[UserBB];
+ ColorVector &ColorsForUserBB = BlockColors[UserBB];
assert(!ColorsForUserBB.empty());
if (ColorsForUserBB.size() > 1 ||
*ColorsForUserBB.begin() != FuncletPadBB)
@@ -1813,10 +809,10 @@ void WinEHPrepare::removeImplausibleTerminators(Function &F) {
// Remove implausible terminators and replace them with UnreachableInst.
for (auto &Funclet : FuncletBlocks) {
BasicBlock *FuncletPadBB = Funclet.first;
- std::set<BasicBlock *> &BlocksInFunclet = Funclet.second;
- Instruction *FirstNonPHI = FuncletPadBB->getFirstNonPHI();
- auto *CatchPad = dyn_cast<CatchPadInst>(FirstNonPHI);
- auto *CleanupPad = dyn_cast<CleanupPadInst>(FirstNonPHI);
+ std::vector<BasicBlock *> &BlocksInFunclet = Funclet.second;
+ Instruction *FuncletPadInst = FuncletPadBB->getFirstNonPHI();
+ auto *CatchPad = dyn_cast<CatchPadInst>(FuncletPadInst);
+ auto *CleanupPad = dyn_cast<CleanupPadInst>(FuncletPadInst);
for (BasicBlock *BB : BlocksInFunclet) {
TerminatorInst *TI = BB->getTerminator();
@@ -1830,34 +826,22 @@ void WinEHPrepare::removeImplausibleTerminators(Function &F) {
bool IsUnreachableCleanupret = false;
if (auto *CRI = dyn_cast<CleanupReturnInst>(TI))
IsUnreachableCleanupret = CRI->getCleanupPad() != CleanupPad;
- // 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) {
+ IsUnreachableCleanupret) {
// Loop through all of our successors and make sure they know that one
// of their predecessors is going away.
for (BasicBlock *SuccBB : TI->successors())
SuccBB->removePredecessor(BB);
- if (IsUnreachableCleanupendpad) {
- // We can't simply replace a cleanupendpad with unreachable, because
- // its predecessor edges are EH edges and unreachable is not an EH
- // pad. Change all predecessors to the "unwind to caller" form.
- for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB);
- PI != PE;) {
- BasicBlock *Pred = *PI++;
- removeUnwindEdge(Pred);
- }
- }
-
new UnreachableInst(BB->getContext(), TI);
TI->eraseFromParent();
+ } else if (isa<InvokeInst>(TI)) {
+ // Invokes within a cleanuppad for the MSVC++ personality never
+ // transfer control to their unwind edge: the personality will
+ // terminate the program.
+ if (Personality == EHPersonality::MSVC_CXX && CleanupPad)
+ removeUnwindEdge(BB);
}
- // FIXME: Check for invokes/cleanuprets/cleanupendpads which unwind to
- // implausible catchendpads (i.e. catchendpad not in immediate parent
- // funclet).
}
}
}
@@ -1886,27 +870,31 @@ void WinEHPrepare::verifyPreparedFunclets(Function &F) {
report_fatal_error("Uncolored BB!");
if (NumColors > 1)
report_fatal_error("Multicolor BB!");
- bool EHPadHasPHI = BB.isEHPad() && isa<PHINode>(BB.begin());
- assert(!EHPadHasPHI && "EH Pad still has a PHI!");
- if (EHPadHasPHI)
- report_fatal_error("EH Pad still has a PHI!");
+ if (!DisableDemotion) {
+ bool EHPadHasPHI = BB.isEHPad() && isa<PHINode>(BB.begin());
+ assert(!EHPadHasPHI && "EH Pad still has a PHI!");
+ if (EHPadHasPHI)
+ report_fatal_error("EH Pad still has a PHI!");
+ }
}
}
-bool WinEHPrepare::prepareExplicitEH(
- Function &F, SmallVectorImpl<BasicBlock *> &EntryBlocks) {
+bool WinEHPrepare::prepareExplicitEH(Function &F) {
+ // Remove unreachable blocks. It is not valuable to assign them a color and
+ // their existence can trick us into thinking values are alive when they are
+ // not.
+ removeUnreachableBlocks(F);
+
replaceTerminatePadWithCleanup(F);
// Determine which blocks are reachable from which funclet entries.
- colorFunclets(F, EntryBlocks);
+ colorFunclets(F);
+
+ cloneCommonBlocks(F);
if (!DisableDemotion)
demotePHIsOnFunclets(F);
- cloneCommonBlocks(F, EntryBlocks);
-
- resolveFuncletAncestry(F, EntryBlocks);
-
if (!DisableCleanups) {
removeImplausibleTerminators(F);
@@ -1917,10 +905,6 @@ bool WinEHPrepare::prepareExplicitEH(
BlockColors.clear();
FuncletBlocks.clear();
- FuncletChildren.clear();
- FuncletParents.clear();
- EstrangedBlocks.clear();
- FuncletCloningRequired = false;
return true;
}
@@ -1930,9 +914,11 @@ bool WinEHPrepare::prepareExplicitEH(
AllocaInst *WinEHPrepare::insertPHILoads(PHINode *PN, Function &F) {
BasicBlock *PHIBlock = PN->getParent();
AllocaInst *SpillSlot = nullptr;
+ Instruction *EHPad = PHIBlock->getFirstNonPHI();
- if (isa<CleanupPadInst>(PHIBlock->getFirstNonPHI())) {
- // Insert a load in place of the PHI and replace all uses.
+ if (!isa<TerminatorInst>(EHPad)) {
+ // If the EHPad isn't a terminator, then we can insert a load in this block
+ // that will dominate all uses.
SpillSlot = new AllocaInst(PN->getType(), nullptr,
Twine(PN->getName(), ".wineh.spillslot"),
&F.getEntryBlock().front());
@@ -1942,16 +928,16 @@ AllocaInst *WinEHPrepare::insertPHILoads(PHINode *PN, Function &F) {
return SpillSlot;
}
+ // Otherwise, we have a PHI on a terminator EHPad, and we give up and insert
+ // loads of the slot before every use.
DenseMap<BasicBlock *, Value *> Loads;
for (Value::use_iterator UI = PN->use_begin(), UE = PN->use_end();
UI != UE;) {
Use &U = *UI++;
auto *UsingInst = cast<Instruction>(U.getUser());
- BasicBlock *UsingBB = UsingInst->getParent();
- if (UsingBB->isEHPad()) {
+ if (isa<PHINode>(UsingInst) && UsingInst->getParent()->isEHPad()) {
// Use is on an EH pad phi. Leave it alone; we'll insert loads and
// stores for it separately.
- assert(isa<PHINode>(UsingInst));
continue;
}
replaceUseWithLoad(PN, U, SpillSlot, Loads, F);
@@ -2005,7 +991,7 @@ void WinEHPrepare::insertPHIStore(
SmallVectorImpl<std::pair<BasicBlock *, Value *>> &Worklist) {
if (PredBlock->isEHPad() &&
- !isa<CleanupPadInst>(PredBlock->getFirstNonPHI())) {
+ isa<TerminatorInst>(PredBlock->getFirstNonPHI())) {
// Pred is unsplittable, so we need to queue it on the worklist.
Worklist.push_back({PredBlock, PredVal});
return;
@@ -2065,10 +1051,10 @@ void WinEHPrepare::replaceUseWithLoad(Value *V, Use &U, AllocaInst *&SpillSlot,
Goto->setSuccessor(0, PHIBlock);
CatchRet->setSuccessor(NewBlock);
// Update the color mapping for the newly split edge.
- SetVector<BasicBlock *> &ColorsForPHIBlock = BlockColors[PHIBlock];
+ ColorVector &ColorsForPHIBlock = BlockColors[PHIBlock];
BlockColors[NewBlock] = ColorsForPHIBlock;
for (BasicBlock *FuncletPad : ColorsForPHIBlock)
- FuncletBlocks[FuncletPad].insert(NewBlock);
+ FuncletBlocks[FuncletPad].push_back(NewBlock);
// Treat the new block as incoming for load insertion.
IncomingBlock = NewBlock;
}
@@ -2087,11 +1073,10 @@ void WinEHPrepare::replaceUseWithLoad(Value *V, Use &U, AllocaInst *&SpillSlot,
}
}
-void WinEHFuncInfo::addIPToStateRange(const BasicBlock *PadBB,
+void WinEHFuncInfo::addIPToStateRange(const InvokeInst *II,
MCSymbol *InvokeBegin,
MCSymbol *InvokeEnd) {
- assert(PadBB->isEHPad() && EHPadStateMap.count(PadBB->getFirstNonPHI()) &&
- "should get EH pad BB with precomputed state");
- InvokeToStateMap[InvokeBegin] =
- std::make_pair(EHPadStateMap[PadBB->getFirstNonPHI()], InvokeEnd);
+ assert(InvokeStateMap.count(II) &&
+ "should get invoke with precomputed state");
+ LabelToStateMap[InvokeBegin] = std::make_pair(InvokeStateMap[II], InvokeEnd);
}
diff --git a/lib/IR/AsmWriter.cpp b/lib/IR/AsmWriter.cpp
index e41815aafa8..fbb27773c11 100644
--- a/lib/IR/AsmWriter.cpp
+++ b/lib/IR/AsmWriter.cpp
@@ -2890,19 +2890,36 @@ void AssemblyWriter::printInstruction(const Instruction &I) {
writeOperand(LPI->getClause(i), true);
}
- } else if (const auto *CPI = dyn_cast<CatchPadInst>(&I)) {
+ } else if (const auto *CatchSwitch = dyn_cast<CatchSwitchInst>(&I)) {
+ Out << " within ";
+ writeOperand(CatchSwitch->getParentPad(), /*PrintType=*/false);
Out << " [";
- for (unsigned Op = 0, NumOps = CPI->getNumArgOperands(); Op < NumOps;
+ unsigned Op = 0;
+ for (const BasicBlock *PadBB : CatchSwitch->handlers()) {
+ if (Op > 0)
+ Out << ", ";
+ writeOperand(PadBB, /*PrintType=*/true);
+ ++Op;
+ }
+ Out << "] unwind ";
+ if (const BasicBlock *UnwindDest = CatchSwitch->getUnwindDest())
+ writeOperand(UnwindDest, /*PrintType=*/true);
+ else
+ Out << "to caller";
+ } else if (const auto *FPI = dyn_cast<FuncletPadInst>(&I)) {
+ Out << " within ";
+ writeOperand(FPI->getParentPad(), /*PrintType=*/false);
+ Out << " [";
+ for (unsigned Op = 0, NumOps = FPI->getNumArgOperands(); Op < NumOps;
++Op) {
if (Op > 0)
Out << ", ";
- writeOperand(CPI->getArgOperand(Op), /*PrintType=*/true);
+ writeOperand(FPI->getArgOperand(Op), /*PrintType=*/true);
}
- Out << "]\n to ";
- writeOperand(CPI->getNormalDest(), /*PrintType=*/true);
- Out << " unwind ";
- writeOperand(CPI->getUnwindDest(), /*PrintType=*/true);
+ Out << ']';
} else if (const auto *TPI = dyn_cast<TerminatePadInst>(&I)) {
+ Out << " within ";
+ writeOperand(TPI->getParentPad(), /*PrintType=*/false);
Out << " [";
for (unsigned Op = 0, NumOps = TPI->getNumArgOperands(); Op < NumOps;
++Op) {
@@ -2915,44 +2932,21 @@ void AssemblyWriter::printInstruction(const Instruction &I) {
writeOperand(TPI->getUnwindDest(), /*PrintType=*/true);
else
Out << "to caller";
- } else if (const auto *CPI = dyn_cast<CleanupPadInst>(&I)) {
- Out << " [";
- for (unsigned Op = 0, NumOps = CPI->getNumOperands(); Op < NumOps; ++Op) {
- if (Op > 0)
- Out << ", ";
- writeOperand(CPI->getOperand(Op), /*PrintType=*/true);
- }
- Out << "]";
} else if (isa<ReturnInst>(I) && !Operand) {
Out << " void";
} else if (const auto *CRI = dyn_cast<CatchReturnInst>(&I)) {
- Out << ' ';
- writeOperand(CRI->getCatchPad(), /*PrintType=*/false);
+ Out << " from ";
+ writeOperand(CRI->getOperand(0), /*PrintType=*/false);
Out << " to ";
- writeOperand(CRI->getSuccessor(), /*PrintType=*/true);
+ writeOperand(CRI->getOperand(1), /*PrintType=*/true);
} else if (const auto *CRI = dyn_cast<CleanupReturnInst>(&I)) {
- Out << ' ';
- writeOperand(CRI->getCleanupPad(), /*PrintType=*/false);
+ Out << " from ";
+ writeOperand(CRI->getOperand(0), /*PrintType=*/false);
Out << " unwind ";
if (CRI->hasUnwindDest())
- writeOperand(CRI->getUnwindDest(), /*PrintType=*/true);
- 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);
+ writeOperand(CRI->getOperand(1), /*PrintType=*/true);
else
Out << "to caller";
} else if (const CallInst *CI = dyn_cast<CallInst>(&I)) {
diff --git a/lib/IR/Dominators.cpp b/lib/IR/Dominators.cpp
index d94e31d4875..b9d4fb7de88 100644
--- a/lib/IR/Dominators.cpp
+++ b/lib/IR/Dominators.cpp
@@ -91,11 +91,11 @@ bool DominatorTree::dominates(const Instruction *Def,
if (Def == User)
return false;
- // The value defined by an invoke/catchpad dominates an instruction only if
- // it dominates every instruction in UseBB.
- // A PHI is dominated only if the instruction dominates every possible use
- // in the UseBB.
- if (isa<InvokeInst>(Def) || isa<CatchPadInst>(Def) || isa<PHINode>(User))
+ // The value defined by an invoke dominates an instruction only if it
+ // dominates every instruction in UseBB.
+ // A PHI is dominated only if the instruction dominates every possible use in
+ // the UseBB.
+ if (isa<InvokeInst>(Def) || isa<PHINode>(User))
return dominates(Def, UseBB);
if (DefBB != UseBB)
@@ -126,18 +126,13 @@ bool DominatorTree::dominates(const Instruction *Def,
if (DefBB == UseBB)
return false;
- // Invoke/CatchPad results are only usable in the normal destination, not in
- // the exceptional destination.
+ // Invoke results are only usable in the normal destination, not in the
+ // exceptional destination.
if (const auto *II = dyn_cast<InvokeInst>(Def)) {
BasicBlock *NormalDest = II->getNormalDest();
BasicBlockEdge E(DefBB, NormalDest);
return dominates(E, UseBB);
}
- if (const auto *CPI = dyn_cast<CatchPadInst>(Def)) {
- BasicBlock *NormalDest = CPI->getNormalDest();
- BasicBlockEdge E(DefBB, NormalDest);
- return dominates(E, UseBB);
- }
return dominates(DefBB, UseBB);
}
@@ -239,8 +234,8 @@ bool DominatorTree::dominates(const Instruction *Def, const Use &U) const {
if (!isReachableFromEntry(DefBB))
return false;
- // Invoke/CatchPad instructions define their return values on the edges
- // to their normal successors, so we have to handle them specially.
+ // Invoke instructions define their return values on the edges to their normal
+ // successors, so we have to handle them specially.
// Among other things, this means they don't dominate anything in
// their own block, except possibly a phi, so we don't need to
// walk the block in any case.
@@ -249,11 +244,6 @@ bool DominatorTree::dominates(const Instruction *Def, const Use &U) const {
BasicBlockEdge E(DefBB, NormalDest);
return dominates(E, U);
}
- if (const auto *CPI = dyn_cast<CatchPadInst>(Def)) {
- BasicBlock *NormalDest = CPI->getNormalDest();
- BasicBlockEdge E(DefBB, NormalDest);
- return dominates(E, U);
- }
// If the def and use are in different blocks, do a simple CFG dominator
// tree query.
diff --git a/lib/IR/Instruction.cpp b/lib/IR/Instruction.cpp
index 7bd50328b12..ce2e1d8c02b 100644
--- a/lib/IR/Instruction.cpp
+++ b/lib/IR/Instruction.cpp
@@ -202,11 +202,10 @@ const char *Instruction::getOpcodeName(unsigned OpCode) {
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 CatchPad: return "catchpad";
+ case CatchSwitch: return "catchswitch";
case TerminatePad: return "terminatepad";
// Standard binary operators...
@@ -476,10 +475,8 @@ bool Instruction::mayThrow() const {
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 *CatchSwitch = dyn_cast<CatchSwitchInst>(this))
+ return CatchSwitch->unwindsToCaller();
if (const auto *TPI = dyn_cast<TerminatePadInst>(this))
return TPI->unwindsToCaller();
return isa<ResumeInst>(this);
diff --git a/lib/IR/Instructions.cpp b/lib/IR/Instructions.cpp
index 11c55865135..82eb1e0f2f7 100644
--- a/lib/IR/Instructions.cpp
+++ b/lib/IR/Instructions.cpp
@@ -764,61 +764,6 @@ BasicBlock *ResumeInst::getSuccessorV(unsigned idx) const {
}
//===----------------------------------------------------------------------===//
-// 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
//===----------------------------------------------------------------------===//
@@ -828,23 +773,22 @@ CleanupReturnInst::CleanupReturnInst(const CleanupReturnInst &CRI)
CRI.getNumOperands(),
CRI.getNumOperands()) {
setInstructionSubclassData(CRI.getSubclassDataFromInstruction());
- Op<-1>() = CRI.Op<-1>();
+ Op<0>() = CRI.Op<0>();
if (CRI.hasUnwindDest())
- Op<-2>() = CRI.Op<-2>();
+ Op<1>() = CRI.Op<1>();
}
-void CleanupReturnInst::init(CleanupPadInst *CleanupPad, BasicBlock *UnwindBB) {
+void CleanupReturnInst::init(Value *CleanupPad, BasicBlock *UnwindBB) {
if (UnwindBB)
setInstructionSubclassData(getSubclassDataFromInstruction() | 1);
- Op<-1>() = CleanupPad;
+ Op<0>() = CleanupPad;
if (UnwindBB)
- Op<-2>() = UnwindBB;
+ Op<1>() = UnwindBB;
}
-CleanupReturnInst::CleanupReturnInst(CleanupPadInst *CleanupPad,
- BasicBlock *UnwindBB, unsigned Values,
- Instruction *InsertBefore)
+CleanupReturnInst::CleanupReturnInst(Value *CleanupPad, BasicBlock *UnwindBB,
+ unsigned Values, Instruction *InsertBefore)
: TerminatorInst(Type::getVoidTy(CleanupPad->getContext()),
Instruction::CleanupRet,
OperandTraits<CleanupReturnInst>::op_end(this) - Values,
@@ -852,9 +796,8 @@ CleanupReturnInst::CleanupReturnInst(CleanupPadInst *CleanupPad,
init(CleanupPad, UnwindBB);
}
-CleanupReturnInst::CleanupReturnInst(CleanupPadInst *CleanupPad,
- BasicBlock *UnwindBB, unsigned Values,
- BasicBlock *InsertAtEnd)
+CleanupReturnInst::CleanupReturnInst(Value *CleanupPad, BasicBlock *UnwindBB,
+ unsigned Values, BasicBlock *InsertAtEnd)
: TerminatorInst(Type::getVoidTy(CleanupPad->getContext()),
Instruction::CleanupRet,
OperandTraits<CleanupReturnInst>::op_end(this) - Values,
@@ -875,58 +818,9 @@ void CleanupReturnInst::setSuccessorV(unsigned Idx, BasicBlock *B) {
}
//===----------------------------------------------------------------------===//
-// CatchEndPadInst Implementation
-//===----------------------------------------------------------------------===//
-
-CatchEndPadInst::CatchEndPadInst(const CatchEndPadInst &CRI)
- : TerminatorInst(CRI.getType(), Instruction::CatchEndPad,
- OperandTraits<CatchEndPadInst>::op_end(this) -
- CRI.getNumOperands(),
- CRI.getNumOperands()) {
- setInstructionSubclassData(CRI.getSubclassDataFromInstruction());
- if (BasicBlock *UnwindDest = CRI.getUnwindDest())
- setUnwindDest(UnwindDest);
-}
-
-void CatchEndPadInst::init(BasicBlock *UnwindBB) {
- if (UnwindBB) {
- setInstructionSubclassData(getSubclassDataFromInstruction() | 1);
- setUnwindDest(UnwindBB);
- }
-}
-
-CatchEndPadInst::CatchEndPadInst(LLVMContext &C, BasicBlock *UnwindBB,
- unsigned Values, Instruction *InsertBefore)
- : TerminatorInst(Type::getVoidTy(C), Instruction::CatchEndPad,
- OperandTraits<CatchEndPadInst>::op_end(this) - Values,
- Values, InsertBefore) {
- init(UnwindBB);
-}
-
-CatchEndPadInst::CatchEndPadInst(LLVMContext &C, BasicBlock *UnwindBB,
- unsigned Values, BasicBlock *InsertAtEnd)
- : TerminatorInst(Type::getVoidTy(C), Instruction::CatchEndPad,
- OperandTraits<CatchEndPadInst>::op_end(this) - Values,
- Values, InsertAtEnd) {
- init(UnwindBB);
-}
-
-BasicBlock *CatchEndPadInst::getSuccessorV(unsigned Idx) const {
- assert(Idx == 0);
- return getUnwindDest();
-}
-unsigned CatchEndPadInst::getNumSuccessorsV() const {
- return getNumSuccessors();
-}
-void CatchEndPadInst::setSuccessorV(unsigned Idx, BasicBlock *B) {
- assert(Idx == 0);
- setUnwindDest(B);
-}
-
-//===----------------------------------------------------------------------===//
// CatchReturnInst Implementation
//===----------------------------------------------------------------------===//
-void CatchReturnInst::init(CatchPadInst *CatchPad, BasicBlock *BB) {
+void CatchReturnInst::init(Value *CatchPad, BasicBlock *BB) {
Op<0>() = CatchPad;
Op<1>() = BB;
}
@@ -938,7 +832,7 @@ CatchReturnInst::CatchReturnInst(const CatchReturnInst &CRI)
Op<1>() = CRI.Op<1>();
}
-CatchReturnInst::CatchReturnInst(CatchPadInst *CatchPad, BasicBlock *BB,
+CatchReturnInst::CatchReturnInst(Value *CatchPad, BasicBlock *BB,
Instruction *InsertBefore)
: TerminatorInst(Type::getVoidTy(BB->getContext()), Instruction::CatchRet,
OperandTraits<CatchReturnInst>::op_begin(this), 2,
@@ -946,7 +840,7 @@ CatchReturnInst::CatchReturnInst(CatchPadInst *CatchPad, BasicBlock *BB,
init(CatchPad, BB);
}
-CatchReturnInst::CatchReturnInst(CatchPadInst *CatchPad, BasicBlock *BB,
+CatchReturnInst::CatchReturnInst(Value *CatchPad, BasicBlock *BB,
BasicBlock *InsertAtEnd)
: TerminatorInst(Type::getVoidTy(BB->getContext()), Instruction::CatchRet,
OperandTraits<CatchReturnInst>::op_begin(this), 2,
@@ -967,64 +861,136 @@ void CatchReturnInst::setSuccessorV(unsigned Idx, BasicBlock *B) {
}
//===----------------------------------------------------------------------===//
-// CatchPadInst Implementation
+// CatchSwitchInst Implementation
//===----------------------------------------------------------------------===//
-void CatchPadInst::init(BasicBlock *IfNormal, BasicBlock *IfException,
- ArrayRef<Value *> Args, const Twine &NameStr) {
- assert(getNumOperands() == 2 + Args.size() && "NumOperands not set up?");
- Op<-2>() = IfNormal;
- Op<-1>() = IfException;
- std::copy(Args.begin(), Args.end(), op_begin());
+
+CatchSwitchInst::CatchSwitchInst(Value *ParentPad, BasicBlock *UnwindDest,
+ unsigned NumReservedValues,
+ const Twine &NameStr,
+ Instruction *InsertBefore)
+ : TerminatorInst(ParentPad->getType(), Instruction::CatchSwitch, nullptr, 0,
+ InsertBefore) {
+ if (UnwindDest)
+ ++NumReservedValues;
+ init(ParentPad, UnwindDest, NumReservedValues + 1);
setName(NameStr);
}
-CatchPadInst::CatchPadInst(const CatchPadInst &CPI)
- : TerminatorInst(CPI.getType(), Instruction::CatchPad,
- OperandTraits<CatchPadInst>::op_end(this) -
- CPI.getNumOperands(),
- CPI.getNumOperands()) {
- std::copy(CPI.op_begin(), CPI.op_end(), op_begin());
+CatchSwitchInst::CatchSwitchInst(Value *ParentPad, BasicBlock *UnwindDest,
+ unsigned NumReservedValues,
+ const Twine &NameStr, BasicBlock *InsertAtEnd)
+ : TerminatorInst(ParentPad->getType(), Instruction::CatchSwitch, nullptr, 0,
+ InsertAtEnd) {
+ if (UnwindDest)
+ ++NumReservedValues;
+ init(ParentPad, UnwindDest, NumReservedValues + 1);
+ setName(NameStr);
}
-CatchPadInst::CatchPadInst(BasicBlock *IfNormal, BasicBlock *IfException,
- ArrayRef<Value *> Args, unsigned Values,
- const Twine &NameStr, Instruction *InsertBefore)
- : TerminatorInst(Type::getTokenTy(IfNormal->getContext()),
- Instruction::CatchPad,
- OperandTraits<CatchPadInst>::op_end(this) - Values, Values,
- InsertBefore) {
- init(IfNormal, IfException, Args, NameStr);
+CatchSwitchInst::CatchSwitchInst(const CatchSwitchInst &CSI)
+ : TerminatorInst(CSI.getType(), Instruction::CatchSwitch, nullptr,
+ CSI.getNumOperands()) {
+ init(CSI.getParentPad(), CSI.getUnwindDest(), CSI.getNumOperands());
+ setNumHungOffUseOperands(ReservedSpace);
+ Use *OL = getOperandList();
+ const Use *InOL = CSI.getOperandList();
+ for (unsigned I = 1, E = ReservedSpace; I != E; ++I)
+ OL[I] = InOL[I];
}
-CatchPadInst::CatchPadInst(BasicBlock *IfNormal, BasicBlock *IfException,
- ArrayRef<Value *> Args, unsigned Values,
- const Twine &NameStr, BasicBlock *InsertAtEnd)
- : TerminatorInst(Type::getTokenTy(IfNormal->getContext()),
- Instruction::CatchPad,
- OperandTraits<CatchPadInst>::op_end(this) - Values, Values,
- InsertAtEnd) {
- init(IfNormal, IfException, Args, NameStr);
+void CatchSwitchInst::init(Value *ParentPad, BasicBlock *UnwindDest,
+ unsigned NumReservedValues) {
+ assert(ParentPad && NumReservedValues);
+
+ ReservedSpace = NumReservedValues;
+ setNumHungOffUseOperands(UnwindDest ? 2 : 1);
+ allocHungoffUses(ReservedSpace);
+
+ Op<0>() = ParentPad;
+ if (UnwindDest) {
+ setInstructionSubclassData(getSubclassDataFromInstruction() | 1);
+ setUnwindDest(UnwindDest);
+ }
}
-BasicBlock *CatchPadInst::getSuccessorV(unsigned Idx) const {
- return getSuccessor(Idx);
+/// growOperands - grow operands - This grows the operand list in response to a
+/// push_back style of operation. This grows the number of ops by 2 times.
+void CatchSwitchInst::growOperands(unsigned Size) {
+ unsigned NumOperands = getNumOperands();
+ assert(NumOperands >= 1);
+ if (ReservedSpace >= NumOperands + Size)
+ return;
+ ReservedSpace = (NumOperands + Size / 2) * 2;
+ growHungoffUses(ReservedSpace);
+}
+
+void CatchSwitchInst::addHandler(BasicBlock *Handler) {
+ unsigned OpNo = getNumOperands();
+ growOperands(1);
+ assert(OpNo < ReservedSpace && "Growing didn't work!");
+ setNumHungOffUseOperands(getNumOperands() + 1);
+ getOperandList()[OpNo] = Handler;
+}
+
+BasicBlock *CatchSwitchInst::getSuccessorV(unsigned idx) const {
+ return getSuccessor(idx);
}
-unsigned CatchPadInst::getNumSuccessorsV() const {
+unsigned CatchSwitchInst::getNumSuccessorsV() const {
return getNumSuccessors();
}
-void CatchPadInst::setSuccessorV(unsigned Idx, BasicBlock *B) {
- return setSuccessor(Idx, B);
+void CatchSwitchInst::setSuccessorV(unsigned idx, BasicBlock *B) {
+ setSuccessor(idx, B);
+}
+
+//===----------------------------------------------------------------------===//
+// FuncletPadInst Implementation
+//===----------------------------------------------------------------------===//
+void FuncletPadInst::init(Value *ParentPad, ArrayRef<Value *> Args,
+ const Twine &NameStr) {
+ assert(getNumOperands() == 1 + Args.size() && "NumOperands not set up?");
+ std::copy(Args.begin(), Args.end(), op_begin());
+ setParentPad(ParentPad);
+ setName(NameStr);
+}
+
+FuncletPadInst::FuncletPadInst(const FuncletPadInst &FPI)
+ : Instruction(FPI.getType(), FPI.getOpcode(),
+ OperandTraits<FuncletPadInst>::op_end(this) -
+ FPI.getNumOperands(),
+ FPI.getNumOperands()) {
+ std::copy(FPI.op_begin(), FPI.op_end(), op_begin());
+ setParentPad(FPI.getParentPad());
+}
+
+FuncletPadInst::FuncletPadInst(Instruction::FuncletPadOps Op, Value *ParentPad,
+ ArrayRef<Value *> Args, unsigned Values,
+ const Twine &NameStr, Instruction *InsertBefore)
+ : Instruction(ParentPad->getType(), Op,
+ OperandTraits<FuncletPadInst>::op_end(this) - Values, Values,
+ InsertBefore) {
+ init(ParentPad, Args, NameStr);
+}
+
+FuncletPadInst::FuncletPadInst(Instruction::FuncletPadOps Op, Value *ParentPad,
+ ArrayRef<Value *> Args, unsigned Values,
+ const Twine &NameStr, BasicBlock *InsertAtEnd)
+ : Instruction(ParentPad->getType(), Op,
+ OperandTraits<FuncletPadInst>::op_end(this) - Values, Values,
+ InsertAtEnd) {
+ init(ParentPad, Args, NameStr);
}
//===----------------------------------------------------------------------===//
// TerminatePadInst Implementation
//===----------------------------------------------------------------------===//
-void TerminatePadInst::init(BasicBlock *BB, ArrayRef<Value *> Args) {
- if (BB)
+void TerminatePadInst::init(Value *ParentPad, BasicBlock *BB,
+ ArrayRef<Value *> Args) {
+ if (BB) {
setInstructionSubclassData(getSubclassDataFromInstruction() | 1);
- if (BB)
- Op<-1>() = BB;
- std::copy(Args.begin(), Args.end(), op_begin());
+ setUnwindDest(BB);
+ }
+ std::copy(Args.begin(), Args.end(), arg_begin());
+ setParentPad(ParentPad);
}
TerminatePadInst::TerminatePadInst(const TerminatePadInst &TPI)
@@ -1036,22 +1002,24 @@ TerminatePadInst::TerminatePadInst(const TerminatePadInst &TPI)
std::copy(TPI.op_begin(), TPI.op_end(), op_begin());
}
-TerminatePadInst::TerminatePadInst(LLVMContext &C, BasicBlock *BB,
+TerminatePadInst::TerminatePadInst(Value *ParentPad, BasicBlock *BB,
ArrayRef<Value *> Args, unsigned Values,
Instruction *InsertBefore)
- : TerminatorInst(Type::getVoidTy(C), Instruction::TerminatePad,
+ : TerminatorInst(Type::getVoidTy(ParentPad->getContext()),
+ Instruction::TerminatePad,
OperandTraits<TerminatePadInst>::op_end(this) - Values,
Values, InsertBefore) {
- init(BB, Args);
+ init(ParentPad, BB, Args);
}
-TerminatePadInst::TerminatePadInst(LLVMContext &C, BasicBlock *BB,
+TerminatePadInst::TerminatePadInst(Value *ParentPad, BasicBlock *BB,
ArrayRef<Value *> Args, unsigned Values,
BasicBlock *InsertAtEnd)
- : TerminatorInst(Type::getVoidTy(C), Instruction::TerminatePad,
+ : TerminatorInst(Type::getVoidTy(ParentPad->getContext()),
+ Instruction::TerminatePad,
OperandTraits<TerminatePadInst>::op_end(this) - Values,
Values, InsertAtEnd) {
- init(BB, Args);
+ init(ParentPad, BB, Args);
}
BasicBlock *TerminatePadInst::getSuccessorV(unsigned Idx) const {
@@ -1067,39 +1035,6 @@ void TerminatePadInst::setSuccessorV(unsigned Idx, BasicBlock *B) {
}
//===----------------------------------------------------------------------===//
-// CleanupPadInst Implementation
-//===----------------------------------------------------------------------===//
-void CleanupPadInst::init(ArrayRef<Value *> Args, const Twine &NameStr) {
- assert(getNumOperands() == Args.size() && "NumOperands not set up?");
- std::copy(Args.begin(), Args.end(), op_begin());
- setName(NameStr);
-}
-
-CleanupPadInst::CleanupPadInst(const CleanupPadInst &CPI)
- : Instruction(CPI.getType(), Instruction::CleanupPad,
- OperandTraits<CleanupPadInst>::op_end(this) -
- CPI.getNumOperands(),
- CPI.getNumOperands()) {
- std::copy(CPI.op_begin(), CPI.op_end(), op_begin());
-}
-
-CleanupPadInst::CleanupPadInst(LLVMContext &C, ArrayRef<Value *> Args,
- const Twine &NameStr, Instruction *InsertBefore)
- : Instruction(Type::getTokenTy(C), Instruction::CleanupPad,
- OperandTraits<CleanupPadInst>::op_end(this) - Args.size(),
- Args.size(), InsertBefore) {
- init(Args, NameStr);
-}
-
-CleanupPadInst::CleanupPadInst(LLVMContext &C, ArrayRef<Value *> Args,
- const Twine &NameStr, BasicBlock *InsertAtEnd)
- : Instruction(Type::getTokenTy(C), Instruction::CleanupPad,
- OperandTraits<CleanupPadInst>::op_end(this) - Args.size(),
- Args.size(), InsertAtEnd) {
- init(Args, NameStr);
-}
-
-//===----------------------------------------------------------------------===//
// UnreachableInst Implementation
//===----------------------------------------------------------------------===//
@@ -4074,32 +4009,24 @@ InvokeInst *InvokeInst::cloneImpl() const {
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);
}
-CatchEndPadInst *CatchEndPadInst::cloneImpl() const {
- return new (getNumOperands()) CatchEndPadInst(*this);
-}
-
CatchReturnInst *CatchReturnInst::cloneImpl() const {
return new (getNumOperands()) CatchReturnInst(*this);
}
-CatchPadInst *CatchPadInst::cloneImpl() const {
- return new (getNumOperands()) CatchPadInst(*this);
+CatchSwitchInst *CatchSwitchInst::cloneImpl() const {
+ return new CatchSwitchInst(*this);
}
-TerminatePadInst *TerminatePadInst::cloneImpl() const {
- return new (getNumOperands()) TerminatePadInst(*this);
+FuncletPadInst *FuncletPadInst::cloneImpl() const {
+ return new (getNumOperands()) FuncletPadInst(*this);
}
-CleanupPadInst *CleanupPadInst::cloneImpl() const {
- return new (getNumOperands()) CleanupPadInst(*this);
+TerminatePadInst *TerminatePadInst::cloneImpl() const {
+ return new (getNumOperands()) TerminatePadInst(*this);
}
UnreachableInst *UnreachableInst::cloneImpl() const {
diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp
index 58f9c5388bf..9862bfcc4fa 100644
--- a/lib/IR/Verifier.cpp
+++ b/lib/IR/Verifier.cpp
@@ -399,9 +399,9 @@ private:
void visitEHPadPredecessors(Instruction &I);
void visitLandingPadInst(LandingPadInst &LPI);
void visitCatchPadInst(CatchPadInst &CPI);
- void visitCatchEndPadInst(CatchEndPadInst &CEPI);
+ void visitCatchReturnInst(CatchReturnInst &CatchReturn);
void visitCleanupPadInst(CleanupPadInst &CPI);
- void visitCleanupEndPadInst(CleanupEndPadInst &CEPI);
+ void visitCatchSwitchInst(CatchSwitchInst &CatchSwitch);
void visitCleanupReturnInst(CleanupReturnInst &CRI);
void visitTerminatePadInst(TerminatePadInst &TPI);
@@ -2885,25 +2885,24 @@ void Verifier::visitEHPadPredecessors(Instruction &I) {
}
return;
}
+ if (auto *CPI = dyn_cast<CatchPadInst>(&I)) {
+ if (!pred_empty(BB))
+ Assert(BB->getUniquePredecessor() == CPI->getCatchSwitch()->getParent(),
+ "Block containg CatchPadInst must be jumped to "
+ "only by its catchswitch.",
+ CPI);
+ return;
+ }
for (BasicBlock *PredBB : predecessors(BB)) {
TerminatorInst *TI = PredBB->getTerminator();
- if (auto *II = dyn_cast<InvokeInst>(TI))
+ if (auto *II = dyn_cast<InvokeInst>(TI)) {
Assert(II->getUnwindDest() == BB && II->getNormalDest() != BB,
"EH pad must be jumped to via an unwind edge", &I, II);
- else if (auto *CPI = dyn_cast<CatchPadInst>(TI))
- Assert(CPI->getUnwindDest() == BB && CPI->getNormalDest() != BB,
- "EH pad must be jumped to via an unwind edge", &I, CPI);
- else if (isa<CatchEndPadInst>(TI))
- ;
- else if (isa<CleanupReturnInst>(TI))
- ;
- else if (isa<CleanupEndPadInst>(TI))
- ;
- else if (isa<TerminatePadInst>(TI))
- ;
- else
+ } else if (!isa<CleanupReturnInst>(TI) && !isa<TerminatePadInst>(TI) &&
+ !isa<CatchSwitchInst>(TI)) {
Assert(false, "EH pad must be jumped to via an unwind edge", &I, TI);
+ }
}
}
@@ -2952,67 +2951,29 @@ void Verifier::visitCatchPadInst(CatchPadInst &CPI) {
visitEHPadPredecessors(CPI);
BasicBlock *BB = CPI.getParent();
+
Function *F = BB->getParent();
Assert(F->hasPersonalityFn(),
"CatchPadInst needs to be in a function with a personality.", &CPI);
+ Assert(isa<CatchSwitchInst>(CPI.getParentPad()),
+ "CatchPadInst needs to be directly nested in a CatchSwitchInst.",
+ CPI.getParentPad());
+
// The catchpad instruction must be the first non-PHI instruction in the
// block.
Assert(BB->getFirstNonPHI() == &CPI,
- "CatchPadInst not the first non-PHI instruction in the block.",
- &CPI);
+ "CatchPadInst not the first non-PHI instruction in the block.", &CPI);
- if (!BB->getSinglePredecessor())
- for (BasicBlock *PredBB : predecessors(BB)) {
- Assert(!isa<CatchPadInst>(PredBB->getTerminator()),
- "CatchPadInst with CatchPadInst predecessor cannot have any other "
- "predecessors.",
- &CPI);
- }
-
- BasicBlock *UnwindDest = CPI.getUnwindDest();
- Instruction *I = UnwindDest->getFirstNonPHI();
- Assert(
- isa<CatchPadInst>(I) || isa<CatchEndPadInst>(I),
- "CatchPadInst must unwind to a CatchPadInst or a CatchEndPadInst.",
- &CPI);
-
- visitTerminatorInst(CPI);
+ visitInstruction(CPI);
}
-void Verifier::visitCatchEndPadInst(CatchEndPadInst &CEPI) {
- visitEHPadPredecessors(CEPI);
-
- BasicBlock *BB = CEPI.getParent();
- Function *F = BB->getParent();
- Assert(F->hasPersonalityFn(),
- "CatchEndPadInst needs to be in a function with a personality.",
- &CEPI);
-
- // The catchendpad instruction must be the first non-PHI instruction in the
- // block.
- Assert(BB->getFirstNonPHI() == &CEPI,
- "CatchEndPadInst not the first non-PHI instruction in the block.",
- &CEPI);
-
- unsigned CatchPadsSeen = 0;
- for (BasicBlock *PredBB : predecessors(BB))
- if (isa<CatchPadInst>(PredBB->getTerminator()))
- ++CatchPadsSeen;
-
- Assert(CatchPadsSeen <= 1, "CatchEndPadInst must have no more than one "
- "CatchPadInst predecessor.",
- &CEPI);
+void Verifier::visitCatchReturnInst(CatchReturnInst &CatchReturn) {
+ Assert(isa<CatchPadInst>(CatchReturn.getOperand(0)),
+ "CatchReturnInst needs to be provided a CatchPad", &CatchReturn,
+ CatchReturn.getOperand(0));
- if (BasicBlock *UnwindDest = CEPI.getUnwindDest()) {
- Instruction *I = UnwindDest->getFirstNonPHI();
- Assert(
- I->isEHPad() && !isa<LandingPadInst>(I),
- "CatchEndPad must unwind to an EH block which is not a landingpad.",
- &CEPI);
- }
-
- visitTerminatorInst(CEPI);
+ visitTerminatorInst(CatchReturn);
}
void Verifier::visitCleanupPadInst(CleanupPadInst &CPI) {
@@ -3030,57 +2991,76 @@ void Verifier::visitCleanupPadInst(CleanupPadInst &CPI) {
"CleanupPadInst not the first non-PHI instruction in the block.",
&CPI);
+ auto *ParentPad = CPI.getParentPad();
+ Assert(isa<CatchSwitchInst>(ParentPad) || isa<ConstantTokenNone>(ParentPad) ||
+ isa<CleanupPadInst>(ParentPad) || isa<CatchPadInst>(ParentPad),
+ "CleanupPadInst has an invalid parent.", &CPI);
+
User *FirstUser = nullptr;
BasicBlock *FirstUnwindDest = nullptr;
for (User *U : CPI.users()) {
BasicBlock *UnwindDest;
if (CleanupReturnInst *CRI = dyn_cast<CleanupReturnInst>(U)) {
UnwindDest = CRI->getUnwindDest();
+ } else if (isa<CleanupPadInst>(U) || isa<CatchSwitchInst>(U) ||
+ isa<TerminatePadInst>(U)) {
+ continue;
} else {
- UnwindDest = cast<CleanupEndPadInst>(U)->getUnwindDest();
+ Assert(false, "bogus cleanuppad use", &CPI);
}
if (!FirstUser) {
FirstUser = U;
FirstUnwindDest = UnwindDest;
} else {
- Assert(UnwindDest == FirstUnwindDest,
- "Cleanuprets/cleanupendpads from the same cleanuppad must "
- "have the same unwind destination",
- FirstUser, U);
+ Assert(
+ UnwindDest == FirstUnwindDest,
+ "cleanupret instructions from the same cleanuppad must have the same "
+ "unwind destination",
+ FirstUser, U);
}
}
visitInstruction(CPI);
}
-void Verifier::visitCleanupEndPadInst(CleanupEndPadInst &CEPI) {
- visitEHPadPredecessors(CEPI);
+void Verifier::visitCatchSwitchInst(CatchSwitchInst &CatchSwitch) {
+ visitEHPadPredecessors(CatchSwitch);
+
+ BasicBlock *BB = CatchSwitch.getParent();
- BasicBlock *BB = CEPI.getParent();
Function *F = BB->getParent();
Assert(F->hasPersonalityFn(),
- "CleanupEndPadInst needs to be in a function with a personality.",
- &CEPI);
+ "CatchSwitchInst needs to be in a function with a personality.",
+ &CatchSwitch);
- // The cleanupendpad instruction must be the first non-PHI instruction in the
+ // The catchswitch 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);
+ Assert(BB->getFirstNonPHI() == &CatchSwitch,
+ "CatchSwitchInst not the first non-PHI instruction in the block.",
+ &CatchSwitch);
- if (BasicBlock *UnwindDest = CEPI.getUnwindDest()) {
+ if (BasicBlock *UnwindDest = CatchSwitch.getUnwindDest()) {
Instruction *I = UnwindDest->getFirstNonPHI();
- Assert(
- I->isEHPad() && !isa<LandingPadInst>(I),
- "CleanupEndPad must unwind to an EH block which is not a landingpad.",
- &CEPI);
+ Assert(I->isEHPad() && !isa<LandingPadInst>(I),
+ "CatchSwitchInst must unwind to an EH block which is not a "
+ "landingpad.",
+ &CatchSwitch);
}
- visitTerminatorInst(CEPI);
+ auto *ParentPad = CatchSwitch.getParentPad();
+ Assert(isa<CatchSwitchInst>(ParentPad) || isa<ConstantTokenNone>(ParentPad) ||
+ isa<CleanupPadInst>(ParentPad) || isa<CatchPadInst>(ParentPad),
+ "CatchSwitchInst has an invalid parent.", ParentPad);
+
+ visitTerminatorInst(CatchSwitch);
}
void Verifier::visitCleanupReturnInst(CleanupReturnInst &CRI) {
+ Assert(isa<CleanupPadInst>(CRI.getOperand(0)),
+ "CleanupReturnInst needs to be provided a CleanupPad", &CRI,
+ CRI.getOperand(0));
+
if (BasicBlock *UnwindDest = CRI.getUnwindDest()) {
Instruction *I = UnwindDest->getFirstNonPHI();
Assert(I->isEHPad() && !isa<LandingPadInst>(I),
@@ -3115,6 +3095,11 @@ void Verifier::visitTerminatePadInst(TerminatePadInst &TPI) {
&TPI);
}
+ auto *ParentPad = TPI.getParentPad();
+ Assert(isa<CatchSwitchInst>(ParentPad) || isa<ConstantTokenNone>(ParentPad) ||
+ isa<CleanupPadInst>(ParentPad) || isa<CatchPadInst>(ParentPad),
+ "TerminatePadInst has an invalid parent.", ParentPad);
+
visitTerminatorInst(TPI);
}
diff --git a/lib/Target/X86/X86WinEHState.cpp b/lib/Target/X86/X86WinEHState.cpp
index 0276f3969b4..7ceb41662ad 100644
--- a/lib/Target/X86/X86WinEHState.cpp
+++ b/lib/Target/X86/X86WinEHState.cpp
@@ -15,6 +15,7 @@
//===----------------------------------------------------------------------===//
#include "X86.h"
+#include "llvm/Analysis/CFG.h"
#include "llvm/Analysis/EHPersonalities.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/Passes.h"
@@ -416,20 +417,33 @@ void WinEHStatePass::addStateStores(Function &F, WinEHFuncInfo &FuncInfo) {
calculateWinCXXEHStateNumbers(&F, FuncInfo);
// Iterate all the instructions and emit state number stores.
+ DenseMap<BasicBlock *, ColorVector> BlockColors = colorEHFunclets(F);
for (BasicBlock &BB : F) {
+ // Figure out what state we should assign calls in this block.
+ int BaseState = -1;
+ auto &BBColors = BlockColors[&BB];
+
+ assert(BBColors.size() == 1 &&
+ "multi-color BB not removed by preparation");
+ BasicBlock *FuncletEntryBB = BBColors.front();
+ if (auto *FuncletPad =
+ dyn_cast<FuncletPadInst>(FuncletEntryBB->getFirstNonPHI())) {
+ auto BaseStateI = FuncInfo.FuncletBaseStateMap.find(FuncletPad);
+ if (BaseStateI != FuncInfo.FuncletBaseStateMap.end())
+ BaseState = BaseStateI->second;
+ }
+
for (Instruction &I : BB) {
if (auto *CI = dyn_cast<CallInst>(&I)) {
// Possibly throwing call instructions have no actions to take after
// an unwind. Ensure they are in the -1 state.
if (CI->doesNotThrow())
continue;
- insertStateNumberStore(RegNode, CI, -1);
+ insertStateNumberStore(RegNode, CI, BaseState);
} else if (auto *II = dyn_cast<InvokeInst>(&I)) {
// Look up the state number of the landingpad this unwinds to.
- Instruction *PadInst = II->getUnwindDest()->getFirstNonPHI();
- // FIXME: Why does this assertion fail?
- //assert(FuncInfo.EHPadStateMap.count(PadInst) && "EH Pad has no state!");
- int State = FuncInfo.EHPadStateMap[PadInst];
+ assert(FuncInfo.InvokeStateMap.count(II) && "invoke has no state!");
+ int State = FuncInfo.InvokeStateMap[II];
insertStateNumberStore(RegNode, II, State);
}
}
diff --git a/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/lib/Transforms/Instrumentation/MemorySanitizer.cpp
index 218e3e96c23..91bb3337509 100644
--- a/lib/Transforms/Instrumentation/MemorySanitizer.cpp
+++ b/lib/Transforms/Instrumentation/MemorySanitizer.cpp
@@ -2684,12 +2684,12 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
setOrigin(&I, getCleanOrigin());
}
- void visitCleanupPadInst(CleanupPadInst &I) {
+ void visitCatchSwitchInst(CatchSwitchInst &I) {
setShadow(&I, getCleanShadow(&I));
setOrigin(&I, getCleanOrigin());
}
- void visitCatchPad(CatchPadInst &I) {
+ void visitFuncletPadInst(FuncletPadInst &I) {
setShadow(&I, getCleanShadow(&I));
setOrigin(&I, getCleanOrigin());
}
@@ -2699,16 +2699,6 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
// Nothing to do here.
}
- void visitCatchEndPadInst(CatchEndPadInst &I) {
- DEBUG(dbgs() << "CatchEndPad: " << I << "\n");
- // Nothing to do here.
- }
-
- void visitCleanupEndPadInst(CleanupEndPadInst &I) {
- DEBUG(dbgs() << "CleanupEndPad: " << I << "\n");
- // Nothing to do here.
- }
-
void visitGetElementPtrInst(GetElementPtrInst &I) {
handleShadowOr(I);
}
diff --git a/lib/Transforms/Scalar/Reassociate.cpp b/lib/Transforms/Scalar/Reassociate.cpp
index fa2f7d995c6..13d9b6d4fee 100644
--- a/lib/Transforms/Scalar/Reassociate.cpp
+++ b/lib/Transforms/Scalar/Reassociate.cpp
@@ -947,8 +947,6 @@ static Value *NegateValue(Value *V, Instruction *BI,
if (Instruction *InstInput = dyn_cast<Instruction>(V)) {
if (InvokeInst *II = dyn_cast<InvokeInst>(InstInput)) {
InsertPt = II->getNormalDest()->begin();
- } else if (auto *CPI = dyn_cast<CatchPadInst>(InstInput)) {
- InsertPt = CPI->getNormalDest()->begin();
} else {
InsertPt = ++InstInput->getIterator();
}
diff --git a/lib/Transforms/Scalar/SCCP.cpp b/lib/Transforms/Scalar/SCCP.cpp
index 52281d4e044..2fca803adde 100644
--- a/lib/Transforms/Scalar/SCCP.cpp
+++ b/lib/Transforms/Scalar/SCCP.cpp
@@ -480,8 +480,10 @@ private:
void visitExtractValueInst(ExtractValueInst &EVI);
void visitInsertValueInst(InsertValueInst &IVI);
void visitLandingPadInst(LandingPadInst &I) { markAnythingOverdefined(&I); }
- void visitCleanupPadInst(CleanupPadInst &CPI) { markAnythingOverdefined(&CPI); }
- void visitCatchPadInst(CatchPadInst &CPI) {
+ void visitFuncletPadInst(FuncletPadInst &FPI) {
+ markAnythingOverdefined(&FPI);
+ }
+ void visitCatchSwitchInst(CatchSwitchInst &CPI) {
markAnythingOverdefined(&CPI);
visitTerminatorInst(CPI);
}
diff --git a/lib/Transforms/Scalar/Sink.cpp b/lib/Transforms/Scalar/Sink.cpp
index 7c0ac7aa6fa..64109b2df11 100644
--- a/lib/Transforms/Scalar/Sink.cpp
+++ b/lib/Transforms/Scalar/Sink.cpp
@@ -169,7 +169,8 @@ static bool isSafeToMove(Instruction *Inst, AliasAnalysis *AA,
return false;
}
- if (isa<TerminatorInst>(Inst) || isa<PHINode>(Inst) || Inst->isEHPad())
+ if (isa<TerminatorInst>(Inst) || isa<PHINode>(Inst) || Inst->isEHPad() ||
+ Inst->mayThrow())
return false;
// Convergent operations cannot be made control-dependent on additional
@@ -194,6 +195,11 @@ bool Sinking::IsAcceptableTarget(Instruction *Inst,
if (Inst->getParent() == SuccToSinkTo)
return false;
+ // It's never legal to sink an instruction into a block which terminates in an
+ // EH-pad.
+ if (SuccToSinkTo->getTerminator()->isExceptional())
+ return false;
+
// If the block has multiple predecessors, this would introduce computation
// on different code paths. We could split the critical edge, but for now we
// just punt.
diff --git a/lib/Transforms/Utils/CodeExtractor.cpp b/lib/Transforms/Utils/CodeExtractor.cpp
index 8ee596e5323..823696d88e6 100644
--- a/lib/Transforms/Utils/CodeExtractor.cpp
+++ b/lib/Transforms/Utils/CodeExtractor.cpp
@@ -560,8 +560,8 @@ emitCallAndSwitchStatement(Function *newFunction, BasicBlock *codeReplacer,
// Restore values just before we exit
Function::arg_iterator OAI = OutputArgBegin;
for (unsigned out = 0, e = outputs.size(); out != e; ++out) {
- // For an invoke/catchpad, the normal destination is the only one
- // that is dominated by the result of the invocation
+ // For an invoke, the normal destination is the only one that is
+ // dominated by the result of the invocation
BasicBlock *DefBlock = cast<Instruction>(outputs[out])->getParent();
bool DominatesDef = true;
@@ -569,8 +569,6 @@ emitCallAndSwitchStatement(Function *newFunction, BasicBlock *codeReplacer,
BasicBlock *NormalDest = nullptr;
if (auto *Invoke = dyn_cast<InvokeInst>(outputs[out]))
NormalDest = Invoke->getNormalDest();
- if (auto *CatchPad = dyn_cast<CatchPadInst>(outputs[out]))
- NormalDest = CatchPad->getNormalDest();
if (NormalDest) {
DefBlock = NormalDest;
diff --git a/lib/Transforms/Utils/InlineFunction.cpp b/lib/Transforms/Utils/InlineFunction.cpp
index cafd1818fed..74ece385581 100644
--- a/lib/Transforms/Utils/InlineFunction.cpp
+++ b/lib/Transforms/Utils/InlineFunction.cpp
@@ -21,6 +21,7 @@
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Analysis/CaptureTracking.h"
+#include "llvm/Analysis/EHPersonalities.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/Attributes.h"
@@ -192,8 +193,6 @@ HandleCallsInBlockInlinedThroughInvoke(BasicBlock *BB, BasicBlock *UnwindEdge) {
// instructions require no special handling.
CallInst *CI = dyn_cast<CallInst>(I);
- // If this call cannot unwind, don't convert it to an invoke.
- // Inline asm calls cannot throw.
if (!CI || CI->doesNotThrow() || isa<InlineAsm>(CI->getCalledValue()))
continue;
@@ -327,40 +326,10 @@ static void HandleInlinedEHPad(InvokeInst *II, BasicBlock *FirstNewBlock,
}
};
- // Forward EH terminator instructions to the caller's invoke destination.
- // This is as simple as connect all the instructions which 'unwind to caller'
- // to the invoke destination.
+ // This connects all the instructions which 'unwind to caller' to the invoke
+ // destination.
for (Function::iterator BB = FirstNewBlock->getIterator(), E = Caller->end();
BB != E; ++BB) {
- Instruction *I = BB->getFirstNonPHI();
- if (I->isEHPad()) {
- if (auto *CEPI = dyn_cast<CatchEndPadInst>(I)) {
- if (CEPI->unwindsToCaller()) {
- CatchEndPadInst::Create(CEPI->getContext(), UnwindDest, CEPI);
- 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;
- for (Value *ArgOperand : TPI->arg_operands())
- TerminatePadArgs.push_back(ArgOperand);
- TerminatePadInst::Create(TPI->getContext(), UnwindDest,
- TerminatePadArgs, TPI);
- TPI->eraseFromParent();
- UpdatePHINodes(&*BB);
- }
- } else {
- assert(isa<CatchPadInst>(I) || isa<CleanupPadInst>(I));
- }
- }
-
if (auto *CRI = dyn_cast<CleanupReturnInst>(BB->getTerminator())) {
if (CRI->unwindsToCaller()) {
CleanupReturnInst::Create(CRI->getCleanupPad(), UnwindDest, CRI);
@@ -368,6 +337,40 @@ static void HandleInlinedEHPad(InvokeInst *II, BasicBlock *FirstNewBlock,
UpdatePHINodes(&*BB);
}
}
+
+ Instruction *I = BB->getFirstNonPHI();
+ if (!I->isEHPad())
+ continue;
+
+ Instruction *Replacement = nullptr;
+ if (auto *TPI = dyn_cast<TerminatePadInst>(I)) {
+ if (TPI->unwindsToCaller()) {
+ SmallVector<Value *, 3> TerminatePadArgs;
+ for (Value *ArgOperand : TPI->arg_operands())
+ TerminatePadArgs.push_back(ArgOperand);
+ Replacement = TerminatePadInst::Create(TPI->getParentPad(), UnwindDest,
+ TerminatePadArgs, TPI);
+ }
+ } else if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(I)) {
+ if (CatchSwitch->unwindsToCaller()) {
+ auto *NewCatchSwitch = CatchSwitchInst::Create(
+ CatchSwitch->getParentPad(), UnwindDest,
+ CatchSwitch->getNumHandlers(), CatchSwitch->getName(),
+ CatchSwitch);
+ for (BasicBlock *PadBB : CatchSwitch->handlers())
+ NewCatchSwitch->addHandler(PadBB);
+ Replacement = NewCatchSwitch;
+ }
+ } else if (!isa<FuncletPadInst>(I)) {
+ llvm_unreachable("unexpected EHPad!");
+ }
+
+ if (Replacement) {
+ Replacement->takeName(I);
+ I->replaceAllUsesWith(Replacement);
+ I->eraseFromParent();
+ UpdatePHINodes(&*BB);
+ }
}
if (InlinedCodeInfo.ContainsCalls)
@@ -1090,6 +1093,53 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI,
return false;
}
+ // We need to figure out which funclet the callsite was in so that we may
+ // properly nest the callee.
+ Instruction *CallSiteEHPad = nullptr;
+ if (CalledPersonality && CallerPersonality) {
+ EHPersonality Personality = classifyEHPersonality(CalledPersonality);
+ if (isFuncletEHPersonality(Personality)) {
+ DenseMap<BasicBlock *, ColorVector> CallerBlockColors =
+ colorEHFunclets(*Caller);
+ ColorVector &CallSiteColors = CallerBlockColors[OrigBB];
+ size_t NumColors = CallSiteColors.size();
+ // There is no single parent, inlining will not succeed.
+ if (NumColors > 1)
+ return false;
+ if (NumColors == 1) {
+ BasicBlock *CallSiteFuncletBB = CallSiteColors.front();
+ if (CallSiteFuncletBB != Caller->begin()) {
+ CallSiteEHPad = CallSiteFuncletBB->getFirstNonPHI();
+ assert(CallSiteEHPad->isEHPad() && "Expected an EHPad!");
+ }
+ }
+
+ // OK, the inlining site is legal. What about the target function?
+
+ if (CallSiteEHPad) {
+ if (Personality == EHPersonality::MSVC_CXX) {
+ // The MSVC personality cannot tolerate catches getting inlined into
+ // cleanup funclets.
+ if (isa<CleanupPadInst>(CallSiteEHPad)) {
+ // Ok, the call site is within a cleanuppad. Let's check the callee
+ // for catchpads.
+ for (const BasicBlock &CalledBB : *CalledFunc) {
+ if (isa<CatchPadInst>(CalledBB.getFirstNonPHI()))
+ return false;
+ }
+ }
+ } else if (isAsynchronousEHPersonality(Personality)) {
+ // SEH is even less tolerant, there may not be any sort of exceptional
+ // funclet in the callee.
+ for (const BasicBlock &CalledBB : *CalledFunc) {
+ if (CalledBB.isEHPad())
+ return false;
+ }
+ }
+ }
+ }
+ }
+
// Get an iterator to the last basic block in the function, which will have
// the new function inlined after it.
Function::iterator LastBlock = --Caller->end();
@@ -1381,6 +1431,30 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI,
}
}
+ // Update the lexical scopes of the new funclets. Anything that had 'none' as
+ // its parent is now nested inside the callsite's EHPad.
+ if (CallSiteEHPad) {
+ for (Function::iterator BB = FirstNewBlock->getIterator(),
+ E = Caller->end();
+ BB != E; ++BB) {
+ Instruction *I = BB->getFirstNonPHI();
+ if (!I->isEHPad())
+ continue;
+
+ if (auto *TPI = dyn_cast<TerminatePadInst>(I)) {
+ if (isa<ConstantTokenNone>(TPI->getParentPad()))
+ TPI->setParentPad(CallSiteEHPad);
+ } else if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(I)) {
+ if (isa<ConstantTokenNone>(CatchSwitch->getParentPad()))
+ CatchSwitch->setParentPad(CallSiteEHPad);
+ } else {
+ auto *FPI = cast<FuncletPadInst>(I);
+ if (isa<ConstantTokenNone>(FPI->getParentPad()))
+ FPI->setParentPad(CallSiteEHPad);
+ }
+ }
+ }
+
// If we are inlining for an invoke instruction, we must make sure to rewrite
// any call instructions into invoke instructions.
if (auto *II = dyn_cast<InvokeInst>(TheCall)) {
diff --git a/lib/Transforms/Utils/LCSSA.cpp b/lib/Transforms/Utils/LCSSA.cpp
index 12a8c71d829..ef2f5042169 100644
--- a/lib/Transforms/Utils/LCSSA.cpp
+++ b/lib/Transforms/Utils/LCSSA.cpp
@@ -84,15 +84,13 @@ static bool processInstruction(Loop &L, Instruction &Inst, DominatorTree &DT,
++NumLCSSA; // We are applying the transformation
- // Invoke/CatchPad instructions are special in that their result value is not
- // available along their unwind edge. The code below tests to see whether
- // DomBB dominates the value, so adjust DomBB to the normal destination block,
+ // Invoke instructions are special in that their result value is not available
+ // along their unwind edge. The code below tests to see whether DomBB
+ // dominates the value, so adjust DomBB to the normal destination block,
// which is effectively where the value is first usable.
BasicBlock *DomBB = Inst.getParent();
if (InvokeInst *Inv = dyn_cast<InvokeInst>(&Inst))
DomBB = Inv->getNormalDest();
- if (auto *CPI = dyn_cast<CatchPadInst>(&Inst))
- DomBB = CPI->getNormalDest();
DomTreeNode *DomNode = DT.getNode(DomBB);
diff --git a/lib/Transforms/Utils/Local.cpp b/lib/Transforms/Utils/Local.cpp
index 391ed685766..cb17b603ae5 100644
--- a/lib/Transforms/Utils/Local.cpp
+++ b/lib/Transforms/Utils/Local.cpp
@@ -1338,19 +1338,22 @@ void llvm::removeUnwindEdge(BasicBlock *BB) {
if (auto *CRI = dyn_cast<CleanupReturnInst>(TI)) {
NewTI = CleanupReturnInst::Create(CRI->getCleanupPad(), nullptr, CRI);
UnwindDest = CRI->getUnwindDest();
- } else if (auto *CEP = dyn_cast<CleanupEndPadInst>(TI)) {
- NewTI = CleanupEndPadInst::Create(CEP->getCleanupPad(), nullptr, CEP);
- UnwindDest = CEP->getUnwindDest();
- } else if (auto *CEP = dyn_cast<CatchEndPadInst>(TI)) {
- NewTI = CatchEndPadInst::Create(CEP->getContext(), nullptr, CEP);
- UnwindDest = CEP->getUnwindDest();
} else if (auto *TPI = dyn_cast<TerminatePadInst>(TI)) {
SmallVector<Value *, 3> TerminatePadArgs;
for (Value *Operand : TPI->arg_operands())
TerminatePadArgs.push_back(Operand);
- NewTI = TerminatePadInst::Create(TPI->getContext(), nullptr,
+ NewTI = TerminatePadInst::Create(TPI->getParentPad(), nullptr,
TerminatePadArgs, TPI);
UnwindDest = TPI->getUnwindDest();
+ } else if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(TI)) {
+ auto *NewCatchSwitch = CatchSwitchInst::Create(
+ CatchSwitch->getParentPad(), nullptr, CatchSwitch->getNumHandlers(),
+ CatchSwitch->getName(), CatchSwitch);
+ for (BasicBlock *PadBB : CatchSwitch->handlers())
+ NewCatchSwitch->addHandler(PadBB);
+
+ NewTI = NewCatchSwitch;
+ UnwindDest = CatchSwitch->getUnwindDest();
} else {
llvm_unreachable("Could not find unwind successor");
}
@@ -1358,6 +1361,7 @@ void llvm::removeUnwindEdge(BasicBlock *BB) {
NewTI->takeName(TI);
NewTI->setDebugLoc(TI->getDebugLoc());
UnwindDest->removePredecessor(BB);
+ TI->replaceAllUsesWith(NewTI);
TI->eraseFromParent();
}
diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp
index fe9fd18292c..cbb8cf234aa 100644
--- a/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -3254,8 +3254,8 @@ bool SimplifyCFGOpt::SimplifyCleanupReturn(CleanupReturnInst *RI) {
// updated to continue to the unwind destination of the cleanup pad being
// simplified.
BasicBlock *BB = RI->getParent();
- Instruction *CPInst = dyn_cast<CleanupPadInst>(BB->getFirstNonPHI());
- if (!CPInst)
+ CleanupPadInst *CPInst = RI->getCleanupPad();
+ if (CPInst->getParent() != BB)
// This isn't an empty cleanup.
return false;
@@ -3265,9 +3265,10 @@ bool SimplifyCFGOpt::SimplifyCleanupReturn(CleanupReturnInst *RI) {
if (!isa<DbgInfoIntrinsic>(I))
return false;
- // If the cleanup return we are simplifying unwinds to the caller, this
- // will set UnwindDest to nullptr.
+ // If the cleanup return we are simplifying unwinds to the caller, this will
+ // set UnwindDest to nullptr.
BasicBlock *UnwindDest = RI->getUnwindDest();
+ Instruction *DestEHPad = UnwindDest ? UnwindDest->getFirstNonPHI() : nullptr;
// We're about to remove BB from the control flow. Before we do, sink any
// PHINodes into the unwind destination. Doing this before changing the
@@ -3278,7 +3279,7 @@ bool SimplifyCFGOpt::SimplifyCleanupReturn(CleanupReturnInst *RI) {
// First, go through the PHI nodes in UnwindDest and update any nodes that
// reference the block we are removing
for (BasicBlock::iterator I = UnwindDest->begin(),
- IE = UnwindDest->getFirstNonPHI()->getIterator();
+ IE = DestEHPad->getIterator();
I != IE; ++I) {
PHINode *DestPN = cast<PHINode>(I);
@@ -3322,7 +3323,7 @@ bool SimplifyCFGOpt::SimplifyCleanupReturn(CleanupReturnInst *RI) {
}
// Sink any remaining PHI nodes directly into UnwindDest.
- Instruction *InsertPt = UnwindDest->getFirstNonPHI();
+ Instruction *InsertPt = DestEHPad;
for (BasicBlock::iterator I = BB->begin(),
IE = BB->getFirstNonPHI()->getIterator();
I != IE;) {
@@ -3492,18 +3493,16 @@ bool SimplifyCFGOpt::SimplifyUnreachable(UnreachableInst *UI) {
}
} else if ((isa<InvokeInst>(TI) &&
cast<InvokeInst>(TI)->getUnwindDest() == BB) ||
- isa<CatchEndPadInst>(TI) || isa<TerminatePadInst>(TI)) {
+ isa<TerminatePadInst>(TI) || isa<CatchSwitchInst>(TI)) {
removeUnwindEdge(TI->getParent());
Changed = true;
- } else if (isa<CleanupReturnInst>(TI) || isa<CleanupEndPadInst>(TI)) {
+ } else if (isa<CleanupReturnInst>(TI)) {
new UnreachableInst(TI->getContext(), TI);
TI->eraseFromParent();
Changed = true;
}
- // TODO: If TI is a CatchPadInst, then (BB must be its normal dest and)
- // we can eliminate it, redirecting its preds to its unwind successor,
- // or to the next outer handler if the removed catch is the last for its
- // catchendpad.
+ // TODO: We can remove a catchswitch if all it's catchpads end in
+ // unreachable.
}
// If this block is now dead, remove it.
diff --git a/test/Assembler/invalid-OperatorConstraint.ll b/test/Assembler/invalid-OperatorConstraint.ll
deleted file mode 100644
index fa90c96c803..00000000000
--- a/test/Assembler/invalid-OperatorConstraint.ll
+++ /dev/null
@@ -1,89 +0,0 @@
-; RUN: sed -e s/.T1:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK1 %s
-; RUN: sed -e s/.T2:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK2 %s
-; RUN: sed -e s/.T3:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK3 %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: ; operator constraint requires an operator
-;T1: catchret undef to label %entry
-;T1: ; CHECK1: [[@LINE-1]]:15: error: Catchpad value required in this position
-;T1: }
-
-;T2: define void @f() {
-;T2: entry:
-;T2: %x = cleanuppad []
-;T2: ; catchret's first operand's operator must be catchpad
-;T2: catchret %x to label %entry
-;T2: ; CHECK2: [[@LINE-1]]:15: error: '%x' is not a catchpad
-;T2: }
-
-;T3: define void @f() {
-;T3: entry:
-;T3: ; catchret's first operand's operator must be catchpad
-;T3: ; (forward reference case)
-;T3: catchret %x to label %next
-;T3: ; CHECK3: [[@LINE-1]]:15: error: '%x' is not a catchpad
-;T3: next:
-;T3: %x = cleanuppad []
-;T3: ret void
-;T3: }
-
-;T4: define void @f() {
-;T4: entry:
-;T4: ; operator constraint requires an operator
-;T4: cleanupret undef unwind label %entry
-;T4: ; CHECK4: [[@LINE-1]]:17: error: Cleanuppad value required in this position
-;T4: }
-
-;T5: define void @f() {
-;T5: entry:
-;T5: %x = catchpad []
-;T5: to label %next unwind label %entry
-;T5: next:
-;T5: ; cleanupret first operand's operator must be cleanuppad
-;T5: cleanupret %x unwind to caller
-;T5: ; CHECK5: [[@LINE-1]]:17: error: '%x' is not a cleanuppad
-;T5: }
-
-;T6: define void @f() {
-;T6: entry:
-;T6: ; cleanupret's first operand's operator must be cleanuppad
-;T6: ; (forward reference case)
-;T6: cleanupret %x unwind label %next
-;T6: ; CHECK6: [[@LINE-1]]:17: error: '%x' is not a cleanuppad
-;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: }
diff --git a/test/Bitcode/compatibility.ll b/test/Bitcode/compatibility.ll
index 6c08a930209..e2a18ebe131 100644
--- a/test/Bitcode/compatibility.ll
+++ b/test/Bitcode/compatibility.ll
@@ -769,95 +769,91 @@ define i32 @instructions.win_eh.1() personality i32 -3 {
entry:
%arg1 = alloca i32
%arg2 = alloca i32
- invoke void @f.ccc() to label %normal unwind label %catchpad1
- invoke void @f.ccc() to label %normal unwind label %catchpad2
- invoke void @f.ccc() to label %normal unwind label %catchpad3
+ invoke void @f.ccc() to label %normal unwind label %catchswitch1
+ invoke void @f.ccc() to label %normal unwind label %catchswitch2
+ invoke void @f.ccc() to label %normal unwind label %catchswitch3
+
+catchswitch1:
+ %cs1 = catchswitch within none [label %catchpad1] unwind label %terminate.1
catchpad1:
- catchpad [] to label %normal unwind label %exn.1
- ; CHECK: catchpad []
- ; CHECK-NEXT: to label %normal unwind label %exn.1
+ catchpad within %cs1 []
+ br label %normal
+ ; CHECK: catchpad within %cs1 []
+ ; CHECK-NEXT: br label %normal
-catchpad2:
- catchpad [i32* %arg1] to label %normal unwind label %exn.2
- ; CHECK: catchpad [i32* %arg1]
- ; CHECK-NEXT: to label %normal unwind label %exn.2
+catchswitch2:
+ %cs2 = catchswitch within none [label %catchpad2] unwind to caller
-catchpad3:
- catchpad [i32* %arg1, i32* %arg2] to label %normal unwind label %exn.3
- ; CHECK: catchpad [i32* %arg1, i32* %arg2]
- ; CHECK-NEXT: to label %normal unwind label %exn.3
-
-exn.1:
- catchendpad unwind label %terminate.1
- ; CHECK: catchendpad unwind label %terminate.1
+catchpad2:
+ catchpad within %cs2 [i32* %arg1]
+ br label %normal
+ ; CHECK: catchpad within %cs2 [i32* %arg1]
+ ; CHECK-NEXT: br label %normal
-exn.2:
- catchendpad unwind to caller
- ; CHECK: catchendpad unwind to caller
+catchswitch3:
+ %cs3 = catchswitch within none [label %catchpad3] unwind label %cleanuppad1
-exn.3:
- catchendpad unwind label %cleanuppad1
- ; CHECK: catchendpad unwind label %cleanuppad1
+catchpad3:
+ catchpad within %cs3 [i32* %arg1, i32* %arg2]
+ br label %normal
+ ; CHECK: catchpad within %cs3 [i32* %arg1, i32* %arg2]
+ ; CHECK-NEXT: br label %normal
cleanuppad1:
- %clean.1 = cleanuppad []
- ; CHECK: %clean.1 = cleanuppad []
- invoke void @f.ccc() to label %normal unwind label %cleanupendpad1
-
-cleanupendpad1:
- cleanupendpad %clean.1 unwind label %terminate.2
- ; CHECK: cleanupendpad %clean.1 unwind label %terminate.2
+ %clean.1 = cleanuppad within none []
+ ; CHECK: %clean.1 = cleanuppad within none []
+ invoke void @f.ccc() to label %normal unwind label %terminate.2
terminate.1:
- terminatepad [] unwind to caller
- ; CHECK: terminatepad [] unwind to caller
+ terminatepad within none [] unwind to caller
+ ; CHECK: terminatepad within none [] unwind to caller
terminate.2:
- terminatepad [i32* %arg1] unwind label %normal.pre
- ; CHECK: terminatepad [i32* %arg1] unwind label %normal.pre
+ terminatepad within %clean.1 [i32* %arg1] unwind label %normal.pre
+ ; CHECK: terminatepad within %clean.1 [i32* %arg1] unwind label %normal.pre
normal.pre:
- terminatepad [i32* %arg1, i32* %arg2] unwind to caller
- ; CHECK: terminatepad [i32* %arg1, i32* %arg2] unwind to caller
+ terminatepad within %clean.1 [i32* %arg1, i32* %arg2] unwind to caller
+ ; CHECK: terminatepad within %clean.1 [i32* %arg1, i32* %arg2] unwind to caller
normal:
ret i32 0
}
-
+;
define i32 @instructions.win_eh.2() personality i32 -4 {
entry:
- invoke void @f.ccc() to label %invoke.cont unwind label %catchpad
+ invoke void @f.ccc() to label %invoke.cont unwind label %catchswitch
invoke.cont:
invoke void @f.ccc() to label %continue unwind label %cleanup
cleanup:
- %clean = cleanuppad []
- ; CHECK: %clean = cleanuppad []
- cleanupret %clean unwind to caller
- ; CHECK: cleanupret %clean unwind to caller
+ %clean = cleanuppad within none []
+ ; CHECK: %clean = cleanuppad within none []
+ cleanupret from %clean unwind to caller
+ ; CHECK: cleanupret from %clean unwind to caller
+
+catchswitch:
+ %cs = catchswitch within none [label %catchpad] unwind label %terminate
catchpad:
- %catch = catchpad [] to label %body unwind label %catchend
- ; CHECK: %catch = catchpad []
- ; CHECK-NEXT: to label %body unwind label %catchend
+ %catch = catchpad within %cs []
+ br label %body
+ ; CHECK: %catch = catchpad within %cs []
+ ; CHECK-NEXT: br label %body
body:
- invoke void @f.ccc() to label %continue unwind label %catchend
- catchret %catch to label %return
- ; CHECK: catchret %catch to label %return
+ invoke void @f.ccc() to label %continue unwind label %terminate
+ catchret from %catch to label %return
+ ; CHECK: catchret from %catch to label %return
return:
ret i32 0
-catchend:
- catchendpad unwind label %terminate
- ; CHECK: catchendpad unwind label %terminate
-
terminate:
- terminatepad [] unwind to caller
- ; CHECK: terminatepad [] unwind to caller
+ terminatepad within %cs [] unwind to caller
+ ; CHECK: terminatepad within %cs [] unwind to caller
continue:
ret i32 0
diff --git a/test/CodeGen/WinEH/wineh-cloning.ll b/test/CodeGen/WinEH/wineh-cloning.ll
index 7d6529d6009..66a9132980f 100644
--- a/test/CodeGen/WinEH/wineh-cloning.ll
+++ b/test/CodeGen/WinEH/wineh-cloning.ll
@@ -1,6 +1,7 @@
-; RUN: opt -mtriple=x86_x64-pc-windows-msvc -S -winehprepare < %s | FileCheck %s
+; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -winehprepare < %s | FileCheck %s
declare i32 @__CxxFrameHandler3(...)
+declare i32 @__C_specific_handler(...)
declare void @f()
declare i32 @g()
@@ -13,16 +14,16 @@ entry:
; %x def colors: {entry} subset of use colors; must spill
%x = call i32 @g()
invoke void @f()
- to label %noreturn unwind label %catch
+ to label %noreturn unwind label %catch.switch
+catch.switch:
+ %cs = catchswitch within none [label %catch] unwind to caller
catch:
- catchpad []
- to label %noreturn unwind label %endcatch
+ catchpad within %cs []
+ br label %noreturn
noreturn:
; %x use colors: {entry, cleanup}
call void @h(i32 %x)
unreachable
-endcatch:
- catchendpad unwind to caller
}
; Need two copies of the call to @h, one under entry and one under catch.
; Currently we generate a load for each, though we shouldn't need one
@@ -32,11 +33,11 @@ endcatch:
; CHECK: %x = call i32 @g()
; CHECK: invoke void @f()
; CHECK: to label %[[EntryCopy:[^ ]+]] unwind label %catch
+; CHECK: catch.switch:
+; CHECK: %cs = catchswitch within none [label %catch] unwind to caller
; CHECK: catch:
-; CHECK: catchpad []
-; CHECK-NEXT: to label %[[CatchCopy:[^ ]+]] unwind
-; CHECK: [[CatchCopy]]:
-; CHECK: call void @h(i32 %x)
+; CHECK: catchpad within %cs []
+; CHECK-NEXT: call void @h(i32 %x)
; CHECK: [[EntryCopy]]:
; CHECK: call void @h(i32 %x)
@@ -46,7 +47,7 @@ entry:
invoke void @f()
to label %exit unwind label %cleanup
cleanup:
- cleanuppad []
+ cleanuppad within none []
br label %exit
exit:
call void @f()
@@ -60,7 +61,7 @@ exit:
; CHECK: invoke void @f()
; CHECK: to label %[[exit:[^ ]+]] unwind label %cleanup
; CHECK: cleanup:
-; CHECK: cleanuppad []
+; CHECK: cleanuppad within none []
; CHECK: call void @f()
; CHECK-NEXT: unreachable
; CHECK: [[exit]]:
@@ -71,16 +72,17 @@ exit:
define void @test3() personality i32 (...)* @__CxxFrameHandler3 {
entry:
invoke void @f()
- to label %invoke.cont unwind label %catch
+ to label %invoke.cont unwind label %catch.switch
invoke.cont:
invoke void @f()
to label %exit unwind label %cleanup
+catch.switch:
+ %cs = catchswitch within none [label %catch] unwind to caller
catch:
- catchpad [] to label %shared unwind label %endcatch
-endcatch:
- catchendpad unwind to caller
+ catchpad within %cs []
+ br label %shared
cleanup:
- cleanuppad []
+ cleanuppad within none []
br label %shared
shared:
call void @f()
@@ -95,13 +97,11 @@ exit:
; CHECK: invoke void @f()
; CHECK: to label %[[exit:[^ ]+]] unwind
; CHECK: catch:
-; CHECK: catchpad []
-; CHECK-NEXT: to label %[[shared:[^ ]+]] unwind
-; CHECK: cleanup:
-; CHECK: cleanuppad []
-; CHECK: call void @f()
+; CHECK: catchpad within %cs []
+; CHECK-NEXT: call void @f()
; CHECK-NEXT: unreachable
-; CHECK: [[shared]]:
+; CHECK: cleanup:
+; CHECK: cleanuppad within none []
; CHECK: call void @f()
; CHECK-NEXT: unreachable
; CHECK: [[exit]]:
@@ -111,12 +111,12 @@ exit:
define void @test4() personality i32 (...)* @__CxxFrameHandler3 {
entry:
invoke void @f()
- to label %shared unwind label %catch
+ to label %shared unwind label %catch.switch
+catch.switch:
+ %cs = catchswitch within none [label %catch] unwind to caller
catch:
- catchpad []
- to label %shared unwind label %endcatch
-endcatch:
- catchendpad unwind to caller
+ catchpad within %cs []
+ br label %shared
shared:
%x = call i32 @g()
%i = call i32 @g()
@@ -145,10 +145,9 @@ exit:
; from %shared to %exit.
; CHECK-LABEL: define void @test4(
; CHECK: entry:
-; CHECK: to label %[[shared_E:[^ ]+]] unwind label %catch
+; CHECK: to label %[[shared_E:[^ ]+]] unwind label %catch.switch
; CHECK: catch:
-; CHECK: to label %[[shared_C:[^ ]+]] unwind label %endcatch
-; CHECK: [[shared_C]]:
+; CHECK: catchpad within %cs []
; CHECK: [[x_C:%[^ ]+]] = call i32 @g()
; CHECK: [[i_C:%[^ ]+]] = call i32 @g()
; CHECK: [[zt_C:%[^ ]+]] = icmp eq i32 [[i_C]], 0
@@ -159,7 +158,7 @@ exit:
; CHECK: [[zt_E:%[^ ]+]] = icmp eq i32 [[i_E]], 0
; CHECK: br i1 [[zt_E]], label %[[exit_E:[^ ]+]], label %[[loop_E:[^ ]+]]
; CHECK: [[loop_C]]:
-; CHECK: [[iloop_C:%[^ ]+]] = phi i32 [ [[i_C]], %[[shared_C]] ], [ [[idec_C:%[^ ]+]], %[[looptail_C:[^ ]+]] ]
+; CHECK: [[iloop_C:%[^ ]+]] = phi i32 [ [[i_C]], %catch ], [ [[idec_C:%[^ ]+]], %[[looptail_C:[^ ]+]] ]
; CHECK: [[b_C:%[^ ]+]] = call i1 @b()
; CHECK: br i1 [[b_C]], label %[[left_C:[^ ]+]], label %[[right_C:[^ ]+]]
; CHECK: [[loop_E]]:
@@ -194,27 +193,25 @@ exit:
; CHECK: unreachable
-define void @test5() personality i32 (...)* @__CxxFrameHandler3 {
+define void @test5() personality i32 (...)* @__C_specific_handler {
entry:
invoke void @f()
to label %exit unwind label %outer
outer:
- %o = cleanuppad []
+ %o = cleanuppad within none []
%x = call i32 @g()
invoke void @f()
- to label %outer.ret unwind label %inner
+ to label %outer.ret unwind label %catch.switch
+catch.switch:
+ %cs = catchswitch within %o [label %inner] unwind to caller
inner:
- %i = catchpad []
- to label %inner.catch unwind label %inner.endcatch
-inner.catch:
- catchret %i to label %outer.post-inner
-inner.endcatch:
- catchendpad unwind to caller
+ %i = catchpad within %cs []
+ catchret from %i to label %outer.post-inner
outer.post-inner:
call void @h(i32 %x)
br label %outer.ret
outer.ret:
- cleanupret %o unwind to caller
+ cleanupret from %o unwind to caller
exit:
ret void
}
@@ -225,17 +222,16 @@ exit:
; CHECK: outer:
; CHECK: %x = call i32 @g()
; CHECK-NEXT: invoke void @f()
-; CHECK-NEXT: to label %outer.ret unwind label %inner
+; CHECK-NEXT: to label %outer.ret unwind label %catch.switch
; CHECK: inner:
-; CHECK: to label %inner.catch unwind label %inner.endcatch
-; CHECK: inner.catch:
-; CHECK-NEXT: catchret %i to label %outer.post-inner
+; CHECK-NEXT: %i = catchpad within %cs []
+; CHECK-NEXT: catchret from %i to label %outer.post-inner
; CHECK: outer.post-inner:
; CHECK-NEXT: call void @h(i32 %x)
; CHECK-NEXT: br label %outer.ret
-define void @test6() personality i32 (...)* @__CxxFrameHandler3 {
+define void @test6() personality i32 (...)* @__C_specific_handler {
entry:
invoke void @f()
to label %invoke.cont unwind label %left
@@ -243,15 +239,13 @@ invoke.cont:
invoke void @f()
to label %exit unwind label %right
left:
- cleanuppad []
+ cleanuppad within none []
br label %shared
right:
- catchpad []
- to label %right.catch unwind label %right.end
+ %cs = catchswitch within none [label %right.catch] unwind to caller
right.catch:
+ catchpad within %cs []
br label %shared
-right.end:
- catchendpad unwind to caller
shared:
%x = call i32 @g()
invoke void @f()
@@ -259,109 +253,32 @@ shared:
shared.cont:
unreachable
inner:
- %i = cleanuppad []
+ %i = cleanuppad within none []
call void @h(i32 %x)
- cleanupret %i unwind label %right.end
+ cleanupret from %i unwind to caller
exit:
ret void
}
-; %inner is a cleanup which appears both as a child of
-; %left and as a child of %right. Since statically we
-; need each funclet to have a single parent, we need to
-; clone the entire %inner funclet so we can have one
-; copy under each parent. The cleanupret in %inner
-; unwinds to the catchendpad for %right, so the copy
-; of %inner under %right should include it; the copy
-; of %inner under %left should instead have an
-; `unreachable` inserted there, but the copy under
-; %left still needs to be created because it's possible
-; the dynamic path enters %left, then enters %inner,
-; then calls @h, and that the call to @h doesn't return.
; CHECK-LABEL: define void @test6(
; CHECK: left:
; CHECK: %x.for.left = call i32 @g()
; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: catchpad
-; CHECK: to label %right.catch unwind label %right.end
+; CHECK: to label %shared.cont.for.left unwind label %inner
; CHECK: right.catch:
+; CHECK: catchpad
; CHECK: %x = call i32 @g()
-; CHECK: to label %shared.cont unwind label %[[INNER_RIGHT:.+]]
-; CHECK: right.end:
-; CHECK: catchendpad unwind to caller
+; CHECK: to label %shared.cont unwind label %inner
; CHECK: shared.cont:
; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: [[I_R:\%.+]] = cleanuppad []
-; CHECK: call void @h(i32 %x)
-; CHECK: cleanupret [[I_R]] unwind label %right.end
-; CHECK: [[INNER_LEFT]]:
-; CHECK: [[I_L:\%.+]] = cleanuppad []
-; CHECK: call void @h(i32 %x.for.left)
-; CHECK: unreachable
-
-
-define void @test7() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %invoke.cont unwind label %left
-invoke.cont:
- invoke void @f()
- to label %unreachable unwind label %right
-left:
- cleanuppad []
- invoke void @f() to label %unreachable unwind label %inner
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- invoke void @f() to label %unreachable unwind label %inner
-right.end:
- catchendpad unwind to caller
-inner:
- %i = cleanuppad []
- %x = call i32 @g()
- call void @h(i32 %x)
- cleanupret %i unwind label %right.end
-unreachable:
- unreachable
-}
-; Another case of a two-parent child (like @test6), this time
-; with the join at the entry itself instead of following a
-; non-pad join.
-; CHECK-LABEL: define void @test7(
-; CHECK: invoke.cont:
-; CHECK: to label %[[UNREACHABLE_ENTRY:.+]] unwind label %right
-; CHECK: left:
-; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: to label %right.catch unwind label %right.end
-; CHECK: right.catch:
-; CHECK: to label %unreachable unwind label %[[INNER_RIGHT:.+]]
-; CHECK: right.end:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: [[I_R:\%.+]] = cleanuppad []
-; CHECK: [[X_R:\%.+]] = call i32 @g()
-; CHECK: call void @h(i32 [[X_R]])
-; CHECK: cleanupret [[I_R]] unwind label %right.end
-; CHECK: [[INNER_LEFT]]:
-; CHECK: [[I_L:\%.+]] = cleanuppad []
-; CHECK: [[X_L:\%.+]] = call i32 @g()
-; CHECK: call void @h(i32 [[X_L]])
-; CHECK: unreachable
-; CHECK: unreachable:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_ENTRY]]:
+; CHECK: shared.cont.for.left:
; CHECK: unreachable
+; CHECK: inner:
+; CHECK: %i = cleanuppad within none []
+; CHECK: call void @h(i32 %x1.wineh.reload)
+; CHECK: cleanupret from %i unwind to caller
-define void @test8() personality i32 (...)* @__CxxFrameHandler3 {
+define void @test9() personality i32 (...)* @__C_specific_handler {
entry:
invoke void @f()
to label %invoke.cont unwind label %left
@@ -369,119 +286,32 @@ invoke.cont:
invoke void @f()
to label %unreachable unwind label %right
left:
- cleanuppad []
- br label %shared
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- invoke void @f()
- to label %unreachable unwind label %inner
-inner:
- cleanuppad []
- invoke void @f()
- to label %unreachable unwind label %inner.child
-inner.child:
- cleanuppad []
- %x = call i32 @g()
- call void @h(i32 %x)
- unreachable
-unreachable:
- unreachable
-}
-; %inner is a two-parent child which itself has a child; need
-; to make two copies of both the %inner and %inner.child.
-; CHECK-LABEL: define void @test8(
-; CHECK: invoke.cont:
-; CHECK: to label %[[UNREACHABLE_ENTRY:.+]] unwind label %right
-; CHECK: left:
-; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: to label %right.catch unwind label %right.end
-; CHECK: right.catch:
-; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: right.end:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: to label %[[UNREACHABLE_INNER_RIGHT:.+]] unwind label %[[INNER_CHILD_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: to label %[[UNREACHABLE_INNER_LEFT:.+]] unwind label %[[INNER_CHILD_LEFT:.+]]
-; CHECK: [[INNER_CHILD_RIGHT]]:
-; CHECK: [[TMP:\%.+]] = cleanuppad []
-; CHECK: [[X:\%.+]] = call i32 @g()
-; CHECK: call void @h(i32 [[X]])
-; CHECK: unreachable
-; CHECK: [[INNER_CHILD_LEFT]]:
-; CHECK: [[TMP:\%.+]] = cleanuppad []
-; CHECK: [[X:\%.+]] = call i32 @g()
-; CHECK: call void @h(i32 [[X]])
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_INNER_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_INNER_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_ENTRY]]:
-; CHECK: unreachable
-
-
-define void @test9() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %invoke.cont unwind label %left
-invoke.cont:
- invoke void @f()
- to label %unreachable unwind label %right
-left:
- cleanuppad []
+ cleanuppad within none []
call void @h(i32 1)
invoke void @f()
to label %unreachable unwind label %right
right:
- cleanuppad []
+ cleanuppad within none []
call void @h(i32 2)
invoke void @f()
to label %unreachable unwind label %left
unreachable:
unreachable
}
-; This is an irreducible loop with two funclets that enter each other;
-; need to make two copies of each funclet (one a child of root, the
-; other a child of the opposite funclet), but also make sure not to
-; clone self-descendants (if we tried to do that we'd need to make an
-; infinite number of them). Presumably if optimizations ever generated
-; such a thing it would mean that one of the two cleanups was originally
-; the parent of the other, but that we'd somehow lost track in the CFG
-; of which was which along the way; generating each possibility lets
-; whichever case was correct execute correctly.
+; This is an irreducible loop with two funclets that enter each other.
; CHECK-LABEL: define void @test9(
; CHECK: entry:
; CHECK: to label %invoke.cont unwind label %[[LEFT:.+]]
; CHECK: invoke.cont:
; CHECK: to label %[[UNREACHABLE_ENTRY:.+]] unwind label %[[RIGHT:.+]]
-; CHECK: [[LEFT_FROM_RIGHT:.+]]:
-; CHECK: call void @h(i32 1)
-; CHECK: call void @f()
-; CHECK: unreachable
; CHECK: [[LEFT]]:
; CHECK: call void @h(i32 1)
; CHECK: invoke void @f()
-; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[RIGHT_FROM_LEFT:.+]]
+; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[RIGHT]]
; CHECK: [[RIGHT]]:
; CHECK: call void @h(i32 2)
; CHECK: invoke void @f()
-; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[LEFT_FROM_RIGHT]]
-; CHECK: [[RIGHT_FROM_LEFT]]:
-; CHECK: call void @h(i32 2)
-; CHECK: call void @f()
-; CHECK: unreachable
+; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[LEFT]]
; CHECK: [[UNREACHABLE_RIGHT]]:
; CHECK: unreachable
; CHECK: [[UNREACHABLE_LEFT]]:
@@ -495,16 +325,16 @@ entry:
invoke void @f()
to label %unreachable unwind label %inner
inner:
- %cleanup = cleanuppad []
+ %cleanup = cleanuppad within none []
; make sure we don't overlook this cleanupret and try to process
; successor %outer as a child of inner.
- cleanupret %cleanup unwind label %outer
+ cleanupret from %cleanup unwind label %outer
outer:
- %catch = catchpad [] to label %catch.body unwind label %endpad
+ %cs = catchswitch within none [label %catch.body] unwind to caller
+
catch.body:
- catchret %catch to label %exit
-endpad:
- catchendpad unwind to caller
+ %catch = catchpad within %cs []
+ catchret from %catch to label %exit
exit:
ret void
unreachable:
@@ -515,46 +345,40 @@ unreachable:
; CHECK-NEXT: invoke
; CHECK-NEXT: to label %unreachable unwind label %inner
; CHECK: inner:
-; CHECK-NEXT: %cleanup = cleanuppad
-; CHECK-NEXT: cleanupret %cleanup unwind label %outer
+; CHECK-NEXT: %cleanup = cleanuppad within none []
+; CHECK-NEXT: cleanupret from %cleanup unwind label %outer
; CHECK: outer:
-; CHECK-NEXT: %catch = catchpad []
-; CHECK-NEXT: to label %catch.body unwind label %endpad
+; CHECK-NEXT: %cs = catchswitch within none [label %catch.body] unwind to caller
; CHECK: catch.body:
-; CHECK-NEXT: catchret %catch to label %exit
-; CHECK: endpad:
-; CHECK-NEXT: catchendpad unwind to caller
+; CHECK-NEXT: %catch = catchpad within %cs []
+; CHECK-NEXT: catchret from %catch to label %exit
; CHECK: exit:
; CHECK-NEXT: ret void
-define void @test11() personality i32 (...)* @__CxxFrameHandler3 {
+define void @test11() personality i32 (...)* @__C_specific_handler {
entry:
invoke void @f()
to label %exit unwind label %cleanup.outer
cleanup.outer:
- %outer = cleanuppad []
+ %outer = cleanuppad within none []
invoke void @f()
to label %outer.cont unwind label %cleanup.inner
outer.cont:
br label %merge
cleanup.inner:
- %inner = cleanuppad []
+ %inner = cleanuppad within %outer []
br label %merge
merge:
- invoke void @f()
- to label %unreachable unwind label %merge.end
-unreachable:
+ call void @f()
unreachable
-merge.end:
- cleanupendpad %outer unwind to caller
exit:
ret void
}
; merge.end will get cloned for outer and inner, but is implausible
-; from inner, so the invoke @f() in inner's copy of merge should be
+; from inner, so the call @f() in inner's copy of merge should be
; rewritten to call @f()
; CHECK-LABEL: define void @test11()
-; CHECK: %inner = cleanuppad []
+; CHECK: %inner = cleanuppad within %outer []
; CHECK-NEXT: call void @f()
; CHECK-NEXT: unreachable
@@ -566,10 +390,10 @@ cont:
invoke void @f()
to label %exit unwind label %right
left:
- cleanuppad []
+ cleanuppad within none []
br label %join
right:
- cleanuppad []
+ cleanuppad within none []
br label %join
join:
; This call will get cloned; make sure we can handle cloning
@@ -587,68 +411,10 @@ entry:
ret void
unreachable:
- cleanuppad []
+ cleanuppad within none []
unreachable
}
-define void @test14() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %exit unwind label %catch1.pad
-catch1.pad:
- %catch1 = catchpad [i32 1]
- to label %catch1.body unwind label %catch2.pad
-catch1.body:
- invoke void @h(i32 1)
- to label %catch1.body2 unwind label %catch.end
-catch1.body2:
- invoke void @f()
- to label %catch1.ret unwind label %cleanup1.pad
-cleanup1.pad:
- %cleanup1 = cleanuppad []
- call void @f()
- cleanupret %cleanup1 unwind label %catch.end
-catch1.ret:
- catchret %catch1 to label %exit
-catch2.pad:
- %catch2 = catchpad [i32 2]
- to label %catch2.body unwind label %catch.end
-catch2.body:
- invoke void @h(i32 2)
- to label %catch2.body2 unwind label %catch.end
-catch2.body2:
- invoke void @f()
- to label %catch2.ret unwind label %cleanup2.pad
-cleanup2.pad:
- %cleanup2 = cleanuppad []
- call void @f()
- cleanupret %cleanup2 unwind label %catch.end
-catch2.ret:
- catchret %catch2 to label %exit
-catch.end:
- catchendpad unwind to caller
-exit:
- ret void
-}
-; Make sure we don't clone the catchendpad even though the
-; cleanupendpads targeting it would naively imply that it
-; should get their respective parent colors (catch1 and catch2),
-; as well as its properly getting the root function color. The
-; references from the invokes ensure that if we did make clones
-; for each catch, they'd be reachable, as those invokes would get
-; rewritten
-; CHECK-LABEL: define void @test14()
-; CHECK-NOT: catchendpad
-; CHECK: invoke void @h(i32 1)
-; CHECK-NEXT: unwind label %catch.end
-; CHECK-NOT: catchendpad
-; CHECK: invoke void @h(i32 2)
-; CHECK-NEXT: unwind label %catch.end
-; CHECK-NOT: catchendpad
-; CHECK: catch.end:
-; CHECK-NEXT: catchendpad
-; CHECK-NOT: catchendpad
-
;; Debug info (from test12)
; Make sure the DISubprogram doesn't get cloned
diff --git a/test/CodeGen/WinEH/wineh-demotion.ll b/test/CodeGen/WinEH/wineh-demotion.ll
index 96f33b0ed1a..bd239133ea8 100644
--- a/test/CodeGen/WinEH/wineh-demotion.ll
+++ b/test/CodeGen/WinEH/wineh-demotion.ll
@@ -1,4 +1,4 @@
-; RUN: opt -mtriple=x86_x64-pc-windows-msvc -S -winehprepare < %s | FileCheck %s
+; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -winehprepare < %s | FileCheck %s
declare i32 @__CxxFrameHandler3(...)
@@ -36,17 +36,15 @@ merge:
; CHECK: merge:
; CHECK-NOT: = phi
%phi = phi i32 [ %x, %left ], [ %y, %right ]
- %cp = catchpad [] to label %catch unwind label %catchend
+ %cs1 = catchswitch within none [label %catch] unwind to caller
catch:
+ %cp = catchpad within %cs1 []
; CHECK: catch:
; CHECK: [[Reload:%[^ ]+]] = load i32, i32* [[Slot]]
; CHECK-NEXT: call void @h(i32 [[Reload]])
call void @h(i32 %phi)
- catchret %cp to label %exit
-
-catchend:
- catchendpad unwind to caller
+ catchret from %cp to label %exit
exit:
ret void
@@ -75,44 +73,42 @@ right:
merge.inner:
; CHECK: merge.inner:
; CHECK-NOT: = phi
- ; CHECK: catchpad []
+ ; CHECK: catchswitch within none
%x = phi i32 [ 1, %left ], [ 2, %right ]
- %cpinner = catchpad [] to label %catch.inner unwind label %catchend.inner
+ %cs1 = catchswitch within none [label %catch.inner] unwind label %merge.outer
catch.inner:
+ %cpinner = catchpad within %cs1 []
; Need just one store here because only %y is affected
; CHECK: catch.inner:
%z = call i32 @g()
; CHECK: store i32 %z
; CHECK-NEXT: invoke void @f
invoke void @f()
- to label %catchret.inner unwind label %catchend.inner
+ to label %catchret.inner unwind label %merge.outer
catchret.inner:
- catchret %cpinner to label %exit
-catchend.inner:
- ; CHECK-NOT: = phi
- %y = phi i32 [ %x, %merge.inner ], [ %z, %catch.inner ]
- catchendpad unwind label %merge.outer
+ catchret from %cpinner to label %exit
merge.outer:
+ %y = phi i32 [ %x, %merge.inner ], [ %z, %catch.inner ]
; CHECK: merge.outer:
- ; CHECK: [[CatchPad:%[^ ]+]] = catchpad []
- %cpouter = catchpad [] to label %catch.outer unwind label %catchend.outer
-
-catchend.outer:
- catchendpad unwind to caller
+ ; CHECK-NOT: = phi
+ ; CHECK: catchswitch within none
+ %cs2 = catchswitch within none [label %catch.outer] unwind to caller
catch.outer:
+ %cpouter = catchpad within %cs2 []
+ ; CHECK: catch.outer:
+ ; CHECK: [[CatchPad:%[^ ]+]] = catchpad within %cs2 []
; Need to load x and y from two different slots since they're both live
; and can have different values (if we came from catch.inner)
- ; CHECK: catch.outer:
; CHECK-DAG: load i32, i32* [[Slot1]]
; CHECK-DAG: load i32, i32* [[Slot2]]
- ; CHECK: catchret [[CatchPad]] to label
+ ; CHECK: catchret from [[CatchPad]] to label
call void @h(i32 %x)
call void @h(i32 %y)
- catchret %cpouter to label %exit
+ catchret from %cpouter to label %exit
exit:
ret void
@@ -145,13 +141,12 @@ right:
to label %join unwind label %catchpad.inner
catchpad.inner:
; CHECK: catchpad.inner:
- ; CHECK-NEXT: catchpad []
+ ; CHECK-NEXT: catchswitch within none
%phi.inner = phi i32 [ %l, %left ], [ %r, %right ]
- %cp1 = catchpad [] to label %catch.inner unwind label %catchend.inner
+ %cs1 = catchswitch within none [label %catch.inner] unwind label %catchpad.outer
catch.inner:
- catchret %cp1 to label %join
-catchend.inner:
- catchendpad unwind label %catchpad.outer
+ %cp1 = catchpad within %cs1 []
+ catchret from %cp1 to label %join
join:
; CHECK: join:
; CHECK-NOT: store
@@ -160,19 +155,19 @@ join:
%j = call i32 @g()
invoke void @f()
to label %exit unwind label %catchpad.outer
+
catchpad.outer:
; CHECK: catchpad.outer:
- ; CHECK-NEXT: catchpad []
- %phi.outer = phi i32 [ %phi.inner, %catchend.inner ], [ %j, %join ]
- %cp2 = catchpad [] to label %catch.outer unwind label %catchend.outer
+ ; CHECK-NEXT: catchswitch within none
+ %phi.outer = phi i32 [ %phi.inner, %catchpad.inner ], [ %j, %join ]
+ %cs2 = catchswitch within none [label %catch.outer] unwind to caller
catch.outer:
; CHECK: catch.outer:
; CHECK: [[Reload:%[^ ]+]] = load i32, i32* [[Slot]]
; CHECK: call void @h(i32 [[Reload]])
+ %cp2 = catchpad within %cs2 []
call void @h(i32 %phi.outer)
- catchret %cp2 to label %exit
-catchend.outer:
- catchendpad unwind to caller
+ catchret from %cp2 to label %exit
exit:
ret void
}
@@ -198,10 +193,10 @@ invoke.cont:
cleanup:
; cleanup phi can be loaded at cleanup entry
; CHECK: cleanup:
- ; CHECK-NEXT: cleanuppad []
+ ; CHECK-NEXT: cleanuppad within none []
; CHECK: [[CleanupReload:%[^ ]+]] = load i32, i32* [[CleanupSlot]]
%phi.cleanup = phi i32 [ 1, %entry ], [ 2, %invoke.cont ]
- %cp = cleanuppad []
+ %cp = cleanuppad within none []
%b = call i1 @i()
br i1 %b, label %left, label %right
@@ -222,7 +217,7 @@ merge:
; CHECK: merge:
; CHECK-NEXT: store i32 [[CleanupReload]], i32* [[CatchSlot:%[^ ]+]]
; CHECK-NEXT: cleanupret
- cleanupret %cp unwind label %catchpad
+ cleanupret from %cp unwind label %catchswitch
invoke.cont2:
; need store for %phi.catch
@@ -230,23 +225,22 @@ invoke.cont2:
; CHECK-NEXT: store i32 3, i32* [[CatchSlot]]
; CHECK-NEXT: invoke void @f
invoke void @f()
- to label %exit unwind label %catchpad
+ to label %exit unwind label %catchswitch
-catchpad:
- ; CHECK: catchpad:
- ; CHECK-NEXT: catchpad []
+catchswitch:
+ ; CHECK: catchswitch:
+ ; CHECK-NEXT: catchswitch within none
%phi.catch = phi i32 [ %phi.cleanup, %merge ], [ 3, %invoke.cont2 ]
- %cp2 = catchpad [] to label %catch unwind label %catchend
+ %cs1 = catchswitch within none [label %catch] unwind to caller
catch:
; CHECK: catch:
+ ; CHECK: catchpad within %cs1
; CHECK: [[CatchReload:%[^ ]+]] = load i32, i32* [[CatchSlot]]
; CHECK: call void @h(i32 [[CatchReload]]
+ %cp2 = catchpad within %cs1 []
call void @h(i32 %phi.catch)
- catchret %cp2 to label %exit
-
-catchend:
- catchendpad unwind to caller
+ catchret from %cp2 to label %exit
exit:
ret void
@@ -262,17 +256,17 @@ entry:
%x = invoke i32 @g()
to label %loop unwind label %to_caller
to_caller:
- %cp1 = cleanuppad []
- cleanupret %cp1 unwind to caller
+ %cp1 = cleanuppad within none []
+ cleanupret from %cp1 unwind to caller
loop:
invoke void @f()
to label %loop unwind label %cleanup
cleanup:
; CHECK: cleanup:
; CHECK: call void @h(i32 %x)
- %cp2 = cleanuppad []
+ %cp2 = cleanuppad within none []
call void @h(i32 %x)
- cleanupret %cp2 unwind to caller
+ cleanupret from %cp2 unwind to caller
}
; CHECK-LABEL: @test7(
@@ -294,18 +288,21 @@ invoke.cont:
catchpad:
; %x phi should be eliminated
; CHECK: catchpad:
- ; CHECK-NEXT: %[[CatchPad:[^ ]+]] = catchpad []
+ ; CHECK-NEXT: catchswitch within none
%x = phi i32 [ 1, %entry ], [ 2, %invoke.cont ]
- %cp = catchpad [] to label %catch unwind label %catchend
+ %cs1 = catchswitch within none [label %catch] unwind to caller
catch:
+ ; CHECK: catch:
+ ; CHECK-NEXT: %[[CatchPad:[^ ]+]] = catchpad within %cs1 []
+ %cp = catchpad within %cs1 []
%b = call i1 @i()
br i1 %b, label %left, label %right
left:
; Edge from %left to %join needs to be split so that
; the load of %x can be inserted *after* the catchret
; CHECK: left:
- ; CHECK-NEXT: catchret %[[CatchPad]] to label %[[SplitLeft:[^ ]+]]
- catchret %cp to label %join
+ ; CHECK-NEXT: catchret from %[[CatchPad]] to label %[[SplitLeft:[^ ]+]]
+ catchret from %cp to label %join
; CHECK: [[SplitLeft]]:
; CHECK: [[LoadX:%[^ ]+]] = load i32, i32* [[SlotX]]
; CHECK: br label %join
@@ -314,11 +311,9 @@ right:
; the load of %y can be inserted *after* the catchret
; CHECK: right:
; CHECK: %y = call i32 @g()
- ; CHECK: catchret %[[CatchPad]] to label %join
+ ; CHECK: catchret from %[[CatchPad]] to label %join
%y = call i32 @g()
- catchret %cp to label %join
-catchend:
- catchendpad unwind to caller
+ catchret from %cp to label %join
join:
; CHECK: join:
; CHECK: %phi = phi i32 [ [[LoadX]], %[[SplitLeft]] ], [ %y, %right ]
@@ -340,20 +335,20 @@ done:
ret void
cleanup1:
- ; CHECK: [[CleanupPad1:%[^ ]+]] = cleanuppad []
+ ; CHECK: [[CleanupPad1:%[^ ]+]] = cleanuppad within none []
; CHECK-NEXT: call void @f()
- ; CHECK-NEXT: cleanupret [[CleanupPad1]]
- %cp0 = cleanuppad []
+ ; CHECK-NEXT: cleanupret from [[CleanupPad1]]
+ %cp0 = cleanuppad within none []
br label %cleanupexit
cleanup2:
- ; CHECK: cleanuppad []
+ ; CHECK: cleanuppad within none []
; CHECK-NEXT: call void @f()
; CHECK-NEXT: unreachable
- %cp1 = cleanuppad []
+ %cp1 = cleanuppad within none []
br label %cleanupexit
cleanupexit:
call void @f()
- cleanupret %cp0 unwind label %cleanup2
+ cleanupret from %cp0 unwind label %cleanup2
}
diff --git a/test/CodeGen/WinEH/wineh-intrinsics.ll b/test/CodeGen/WinEH/wineh-intrinsics.ll
index acdeb796ac1..3658792a384 100644
--- a/test/CodeGen/WinEH/wineh-intrinsics.ll
+++ b/test/CodeGen/WinEH/wineh-intrinsics.ll
@@ -15,13 +15,12 @@ entry:
invoke void (...) @f(i32 1)
to label %exit unwind label %catchpad
catchpad:
- %catch = catchpad [i32 1] to label %do_catch unwind label %catchend
+ %cs1 = catchswitch within none [label %do_catch] unwind to caller
do_catch:
+ %catch = catchpad within %cs1 [i32 1]
%exn = call i8* @llvm.eh.exceptionpointer.p0i8(token %catch)
call void (...) @f(i8* %exn)
- catchret %catch to label %exit
-catchend:
- catchendpad unwind to caller
+ catchret from %catch to label %exit
exit:
ret void
}
@@ -31,13 +30,12 @@ entry:
invoke void (...) @f(i32 1)
to label %exit unwind label %catchpad
catchpad:
- %catch = catchpad [i32 1] to label %do_catch unwind label %catchend
+ %cs1 = catchswitch within none [label %do_catch] unwind to caller
do_catch:
+ %catch = catchpad within %cs1 [i32 1]
%exn = call i8 addrspace(1)* @llvm.eh.exceptionpointer.p1i8(token %catch)
call void (...) @f(i8 addrspace(1)* %exn)
- catchret %catch to label %exit
-catchend:
- catchendpad unwind to caller
+ catchret from %catch to label %exit
exit:
ret void
}
diff --git a/test/CodeGen/WinEH/wineh-multi-parent-cloning.ll b/test/CodeGen/WinEH/wineh-multi-parent-cloning.ll
deleted file mode 100644
index 1e9342d17cb..00000000000
--- a/test/CodeGen/WinEH/wineh-multi-parent-cloning.ll
+++ /dev/null
@@ -1,1548 +0,0 @@
-; RUN: opt -mtriple=x86_x64-pc-windows-msvc -S -winehprepare < %s | FileCheck %s
-
-declare i32 @__CxxFrameHandler3(...)
-
-declare void @f()
-declare i32 @g()
-declare void @h(i32)
-declare i1 @b()
-
-define void @test1() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %invoke.cont unwind label %left
-invoke.cont:
- invoke void @f()
- to label %exit unwind label %right
-left:
- cleanuppad []
- br label %shared
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- %x = call i32 @g()
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- %i = cleanuppad []
- call void @h(i32 %x)
- cleanupret %i unwind label %right.end
-exit:
- ret void
-}
-; %inner is a cleanup which appears both as a child of
-; %left and as a child of %right. Since statically we
-; need each funclet to have a single parent, we need to
-; clone the entire %inner funclet so we can have one
-; copy under each parent. The cleanupret in %inner
-; unwinds to the catchendpad for %right, so the copy
-; of %inner under %right should include it; the copy
-; of %inner under %left should instead have an
-; `unreachable` inserted there, but the copy under
-; %left still needs to be created because it's possible
-; the dynamic path enters %left, then enters %inner,
-; then calls @h, and that the call to @h doesn't return.
-; CHECK-LABEL: define void @test1(
-; CHECK: left:
-; CHECK: cleanuppad
-; CHECK: %x.for.left = call i32 @g()
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: to label %right.catch unwind label %right.end
-; CHECK: right.catch:
-; CHECK: %x = call i32 @g()
-; CHECK: to label %shared.cont unwind label %[[INNER_RIGHT:.+]]
-; CHECK: right.end:
-; CHECK: catchendpad unwind to caller
-; CHECK: shared.cont:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: [[I_R:\%.+]] = cleanuppad []
-; CHECK: call void @h(i32 %x)
-; CHECK: cleanupret [[I_R]] unwind label %right.end
-; CHECK: [[INNER_LEFT]]:
-; CHECK: [[I_L:\%.+]] = cleanuppad []
-; CHECK: call void @h(i32 %x.for.left)
-; CHECK: unreachable
-
-
-define void @test2() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %invoke.cont unwind label %left
-invoke.cont:
- invoke void @f()
- to label %exit unwind label %right
-left:
- cleanuppad []
- br label %shared
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- %x = call i32 @g()
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 %x)
- unreachable
-inner.end:
- catchendpad unwind label %right.end
-exit:
- ret void
-}
-; In this case left and right are both parents of inner. This differs from
-; @test1 in that inner is a catchpad rather than a cleanuppad, which makes
-; inner.end a block that gets cloned so that left and right each contain a
-; copy (catchendpad blocks are considered to be part of the parent funclet
-; of the associated catchpad). The catchendpad in %inner.end unwinds to
-; %right.end (which belongs to the entry funclet).
-; CHECK-LABEL: define void @test2(
-; CHECK: left:
-; CHECK: cleanuppad
-; CHECK: %x.for.left = call i32 @g()
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: to label %right.catch unwind label %[[RIGHT_END:.+]]
-; CHECK: right.catch:
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: call void @h(i32 %x)
-; CHECK: unreachable
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: call void @h(i32 %x.for.left)
-; CHECK: unreachable
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind label %[[RIGHT_END]]
-
-define void @test3() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %exit unwind label %left
-left:
- %l = cleanuppad []
- br label %shared
-left.end:
- cleanupendpad %l unwind label %right
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- %x = call i32 @g()
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 %x)
- unreachable
-inner.end:
- catchendpad unwind label %left.end
-exit:
- ret void
-}
-; In this case, %left and %right are siblings with %entry as the parent of both,
-; while %left and %right are both parents of %inner. The catchendpad in
-; %inner.end unwinds to %left.end. When %inner is cloned a copy of %inner.end
-; will be made for both %left and %right, but because %left.end is a cleanup pad
-; and %right is a catch pad the unwind edge from the copy of %inner.end for
-; %right must be removed.
-; CHECK-LABEL: define void @test3(
-; CHECK: left:
-; CHECK: %l = cleanuppad []
-; CHECK: %x.for.left = call i32 @g()
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: [[LEFT_END:left.end.*]]:
-; CHECK: cleanupendpad %l unwind label %right
-; CHECK: right:
-; CHECK: to label %right.catch unwind label %[[RIGHT_END:.+]]
-; CHECK: right.catch:
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: call void @h(i32 %x)
-; CHECK: unreachable
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: call void @h(i32 %x.for.left)
-; CHECK: unreachable
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind label %[[LEFT_END]]
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind to caller
-
-
-define void @test4() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %exit unwind label %left
-left:
- catchpad []
- to label %left.catch unwind label %left.end
-left.catch:
- br label %shared
-left.end:
- catchendpad unwind label %right
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- %x = call i32 @g()
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 %x)
- unreachable
-inner.end:
- catchendpad unwind label %left.end
-exit:
- ret void
-}
-; This is a variation of @test3 in which both %left and %right are catch pads.
-; In this case, %left and %right are siblings with %entry as the parent of both,
-; while %left and %right are both parents of %inner. The catchendpad in
-; %inner.end unwinds to %left.end. When %inner is cloned a copy of %inner.end
-; will be made for both %left and %right, but because the catchpad in %right
-; does not unwind to %left.end the unwind edge from the copy of %inner.end for
-; %right must be removed.
-; CHECK-LABEL: define void @test4(
-; CHECK: left:
-; CHECK: catchpad []
-; CHECK: to label %left.catch unwind label %[[LEFT_END:.+]]
-; CHECK: left.catch:
-; CHECK: %x.for.left = call i32 @g()
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: [[LEFT_END]]:
-; CHECK: catchendpad unwind label %right
-; CHECK: right:
-; CHECK: to label %right.catch unwind label %[[RIGHT_END:.+]]
-; CHECK: right.catch:
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: call void @h(i32 %x)
-; CHECK: unreachable
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: call void @h(i32 %x.for.left)
-; CHECK: unreachable
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind label %[[LEFT_END]]
-
-
-define void @test5() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %exit unwind label %left
-left:
- catchpad []
- to label %left.catch unwind label %left.end
-left.catch:
- br label %shared
-left.end:
- catchendpad unwind label %right
-right:
- %r = cleanuppad []
- br label %shared
-shared:
- %x = call i32 @g()
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 %x)
- unreachable
-inner.end:
- catchendpad unwind label %left.end
-exit:
- ret void
-}
-; Like @test3, %left and %right are siblings with %entry as the parent of both,
-; while %left and %right are both parents of %inner. This case makes %left a
-; catch and %right a cleanup so that %inner unwinds to %left.end, which is a
-; block in %entry. The %inner funclet is cloned for %left and %right, but the
-; copy of %inner.end for %right must have its unwind edge removed because the
-; catchendpad at %left.end is not compatible with %right.
-; CHECK-LABEL: define void @test5(
-; CHECK: left:
-; CHECK: catchpad []
-; CHECK: to label %left.catch unwind label %[[LEFT_END:.+]]
-; CHECK: left.catch:
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: [[LEFT_END]]:
-; CHECK: catchendpad unwind label %right
-; CHECK: right:
-; CHECK: %r = cleanuppad []
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: call void @h(i32 %x)
-; CHECK: unreachable
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: call void @h(i32 %x.for.left)
-; CHECK: unreachable
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind label %[[LEFT_END]]
-
-define void @test6() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %exit unwind label %left
-left:
- catchpad []
- to label %left.catch unwind label %left.end
-left.catch:
- br label %shared
-left.end:
- catchendpad unwind label %middle
-middle:
- %m = catchpad []
- to label %middle.catch unwind label %middle.end
-middle.catch:
- catchret %m to label %exit
-middle.end:
- catchendpad unwind label %right
-right:
- %r = cleanuppad []
- br label %shared
-shared:
- %x = call i32 @g()
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 %x)
- unreachable
-inner.end:
- catchendpad unwind label %left.end
-exit:
- ret void
-}
-; This is like @test5 but it inserts another sibling between %left and %right.
-; In this case %left, %middle and %right are all siblings, while %left and
-; %right are both parents of %inner. This checks the proper handling of the
-; catchendpad in %inner.end (which will be cloned so that %left and %right both
-; have copies) unwinding to a catchendpad that unwinds to a sibling.
-; CHECK-LABEL: define void @test6(
-; CHECK: left:
-; CHECK: catchpad []
-; CHECK: to label %left.catch unwind label %[[LEFT_END:.+]]
-; CHECK: left.catch:
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: [[LEFT_END]]:
-; CHECK: catchendpad unwind label %middle
-; CHECK: middle:
-; CHECK: catchpad []
-; CHECK: to label %middle.catch unwind label %middle.end
-; CHECK: middle.catch:
-; CHECK: catchret %m to label %exit
-; CHECK: middle.end:
-; CHECK: catchendpad unwind label %right
-; CHECK: right:
-; CHECK: %r = cleanuppad []
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: call void @h(i32 %x)
-; CHECK: unreachable
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: call void @h(i32 %x.for.left)
-; CHECK: unreachable
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind label %[[LEFT_END]]
-
-
-define void @test7() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %exit unwind label %left
-left:
- catchpad []
- to label %left.catch unwind label %left.end
-left.catch:
- br label %shared
-left.end:
- catchendpad unwind label %right
-right:
- %r = cleanuppad []
- br label %shared
-shared:
- %x = call i32 @g()
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 %x)
- unreachable
-inner.end:
- catchendpad unwind label %inner.sibling
-inner.sibling:
- %is = cleanuppad []
- call void @h(i32 0)
- cleanupret %is unwind label %left.end
-exit:
- ret void
-}
-; This is like @test5 but instead of unwinding to %left.end, the catchendpad
-; in %inner.end unwinds to a sibling cleanup pad. Both %inner (along with its
-; associated blocks) and %inner.sibling must be cloned for %left and %right.
-; The clones of %inner will be identical, but the copy of %inner.sibling for
-; %right must end with an unreachable instruction, because it cannot unwind to
-; %left.end.
-; CHECK-LABEL: define void @test7(
-; CHECK: left:
-; CHECK: catchpad []
-; CHECK: to label %left.catch unwind label %[[LEFT_END:.+]]
-; CHECK: left.catch:
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: [[LEFT_END]]:
-; CHECK: catchendpad unwind label %[[RIGHT:.+]]
-; CHECK: [[RIGHT]]:
-; CHECK: [[R:\%.+]] = cleanuppad []
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: call void @h(i32 %x)
-; CHECK: unreachable
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: call void @h(i32 %x.for.left)
-; CHECK: unreachable
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind label %[[INNER_SIBLING_RIGHT:.+]]
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind label %[[INNER_SIBLING_LEFT:.+]]
-; CHECK: [[INNER_SIBLING_RIGHT]]
-; CHECK: [[IS_R:\%.+]] = cleanuppad []
-; CHECK: call void @h(i32 0)
-; CHECK: unreachable
-; CHECK: [[INNER_SIBLING_LEFT]]
-; CHECK: [[IS_L:\%.+]] = cleanuppad []
-; CHECK: call void @h(i32 0)
-; CHECK: cleanupret [[IS_L]] unwind label %[[LEFT_END]]
-
-
-define void @test8() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %invoke.cont unwind label %left
-invoke.cont:
- invoke void @f()
- to label %unreachable unwind label %right
-left:
- cleanuppad []
- invoke void @f() to label %unreachable unwind label %inner
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- invoke void @f() to label %unreachable unwind label %inner
-right.end:
- catchendpad unwind to caller
-inner:
- %i = cleanuppad []
- %x = call i32 @g()
- call void @h(i32 %x)
- cleanupret %i unwind label %right.end
-unreachable:
- unreachable
-}
-; Another case of a two-parent child (like @test1), this time
-; with the join at the entry itself instead of following a
-; non-pad join.
-; CHECK-LABEL: define void @test8(
-; CHECK: invoke.cont:
-; CHECK: to label %[[UNREACHABLE_ENTRY:.+]] unwind label %right
-; CHECK: left:
-; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: to label %right.catch unwind label %right.end
-; CHECK: right.catch:
-; CHECK: to label %unreachable unwind label %[[INNER_RIGHT:.+]]
-; CHECK: right.end:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: [[I_R:\%.+]] = cleanuppad []
-; CHECK: [[X_R:\%.+]] = call i32 @g()
-; CHECK: call void @h(i32 [[X_R]])
-; CHECK: cleanupret [[I_R]] unwind label %right.end
-; CHECK: [[INNER_LEFT]]:
-; CHECK: [[I_L:\%.+]] = cleanuppad []
-; CHECK: [[X_L:\%.+]] = call i32 @g()
-; CHECK: call void @h(i32 [[X_L]])
-; CHECK: unreachable
-; CHECK: unreachable:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_ENTRY]]:
-; CHECK: unreachable
-
-
-define void @test9() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %invoke.cont unwind label %left
-invoke.cont:
- invoke void @f()
- to label %unreachable unwind label %right
-left:
- cleanuppad []
- br label %shared
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- invoke void @f()
- to label %unreachable unwind label %inner
-inner:
- cleanuppad []
- invoke void @f()
- to label %unreachable unwind label %inner.child
-inner.child:
- cleanuppad []
- %x = call i32 @g()
- call void @h(i32 %x)
- unreachable
-unreachable:
- unreachable
-}
-; %inner is a two-parent child which itself has a child; need
-; to make two copies of both the %inner and %inner.child.
-; CHECK-LABEL: define void @test9(
-; CHECK: invoke.cont:
-; CHECK: to label %[[UNREACHABLE_ENTRY:.+]] unwind label %right
-; CHECK: left:
-; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: to label %right.catch unwind label %right.end
-; CHECK: right.catch:
-; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: right.end:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: to label %[[UNREACHABLE_INNER_RIGHT:.+]] unwind label %[[INNER_CHILD_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: to label %[[UNREACHABLE_INNER_LEFT:.+]] unwind label %[[INNER_CHILD_LEFT:.+]]
-; CHECK: [[INNER_CHILD_RIGHT]]:
-; CHECK: [[TMP:\%.+]] = cleanuppad []
-; CHECK: [[X:\%.+]] = call i32 @g()
-; CHECK: call void @h(i32 [[X]])
-; CHECK: unreachable
-; CHECK: [[INNER_CHILD_LEFT]]:
-; CHECK: [[TMP:\%.+]] = cleanuppad []
-; CHECK: [[X:\%.+]] = call i32 @g()
-; CHECK: call void @h(i32 [[X]])
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_INNER_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_INNER_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_ENTRY]]:
-; CHECK: unreachable
-
-
-define void @test10() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %invoke.cont unwind label %left
-invoke.cont:
- invoke void @f()
- to label %unreachable unwind label %right
-left:
- cleanuppad []
- call void @h(i32 1)
- invoke void @f()
- to label %unreachable unwind label %right
-right:
- cleanuppad []
- call void @h(i32 2)
- invoke void @f()
- to label %unreachable unwind label %left
-unreachable:
- unreachable
-}
-; This is an irreducible loop with two funclets that enter each other;
-; need to make two copies of each funclet (one a child of root, the
-; other a child of the opposite funclet), but also make sure not to
-; clone self-descendants (if we tried to do that we'd need to make an
-; infinite number of them). Presumably if optimizations ever generated
-; such a thing it would mean that one of the two cleanups was originally
-; the parent of the other, but that we'd somehow lost track in the CFG
-; of which was which along the way; generating each possibility lets
-; whichever case was correct execute correctly.
-; CHECK-LABEL: define void @test10(
-; CHECK: entry:
-; CHECK: to label %invoke.cont unwind label %[[LEFT:.+]]
-; CHECK: invoke.cont:
-; CHECK: to label %[[UNREACHABLE_ENTRY:.+]] unwind label %[[RIGHT:.+]]
-; CHECK: [[LEFT_FROM_RIGHT:.+]]:
-; CHECK: call void @h(i32 1)
-; CHECK: call void @f()
-; CHECK: unreachable
-; CHECK: [[LEFT]]:
-; CHECK: call void @h(i32 1)
-; CHECK: invoke void @f()
-; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[RIGHT_FROM_LEFT:.+]]
-; CHECK: [[RIGHT]]:
-; CHECK: call void @h(i32 2)
-; CHECK: invoke void @f()
-; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[LEFT_FROM_RIGHT]]
-; CHECK: [[RIGHT_FROM_LEFT]]:
-; CHECK: call void @h(i32 2)
-; CHECK: call void @f()
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_ENTRY]]:
-; CHECK: unreachable
-
-
-define void @test11() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %exit unwind label %left
-left:
- catchpad []
- to label %left.catch unwind label %left.sibling
-left.catch:
- br label %shared
-left.sibling:
- %ls = catchpad []
- to label %left.sibling.catch unwind label %left.end
-left.sibling.catch:
- catchret %ls to label %exit
-left.end:
- catchendpad unwind label %right
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- %x = call i32 @g()
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 %x)
- unreachable
-inner.end:
- catchendpad unwind label %left.end
-exit:
- ret void
-}
-; This is a variation of @test4 in which the shared child funclet unwinds to a
-; catchend pad that is the unwind destination of %left.sibling rather than %left
-; but is still a valid destination for %inner as reach from %left.
-; When %inner is cloned a copy of %inner.end will be made for both %left and
-; %right, but because the catchpad in %right does not unwind to %left.end the
-; unwind edge from the copy of %inner.end for %right must be removed.
-; CHECK-LABEL: define void @test11(
-; CHECK: left:
-; CHECK: catchpad []
-; CHECK: to label %left.catch unwind label %left.sibling
-; CHECK: left.catch:
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: left.sibling:
-; CHECK: catchpad []
-; CHECK: to label %left.sibling.catch unwind label %[[LEFT_END:.+]]
-; CHECK: [[LEFT_END]]:
-; CHECK: catchendpad unwind label %right
-; CHECK: right:
-; CHECK: to label %right.catch unwind label %[[RIGHT_END:.+]]
-; CHECK: right.catch:
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: call void @h(i32 %x)
-; CHECK: unreachable
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: call void @h(i32 %x.for.left)
-; CHECK: unreachable
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind label %[[LEFT_END]]
-
-
-define void @test12() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %exit unwind label %left
-left:
- catchpad []
- to label %left.catch unwind label %right
-left.catch:
- br label %shared
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- %x = call i32 @g()
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 %x)
- unreachable
-inner.end:
- catchendpad unwind label %right.end
-exit:
- ret void
-}
-; In this case %left and %right are both parents of %inner, so %inner must be
-; cloned but the catchendpad unwind target in %inner.end is valid for both
-; parents, so the unwind edge should not be removed in either case.
-; CHECK-LABEL: define void @test12(
-; CHECK: left:
-; CHECK: catchpad []
-; CHECK: to label %left.catch unwind label %right
-; CHECK: left.catch:
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: to label %right.catch unwind label %[[RIGHT_END:.+]]
-; CHECK: right.catch:
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: call void @h(i32 %x)
-; CHECK: unreachable
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: call void @h(i32 %x.for.left)
-; CHECK: unreachable
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind label %[[RIGHT_END]]
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind label %[[RIGHT_END]]
-
-define void @test13() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %invoke.cont unwind label %left
-invoke.cont:
- invoke void @f()
- to label %exit unwind label %right
-left:
- %l = catchpad []
- to label %left.cont unwind label %left.end
-left.cont:
- invoke void @f()
- to label %left.ret unwind label %inner
-left.ret:
- catchret %l to label %invoke.cont
-left.end:
- catchendpad unwind to caller
-right:
- %r = catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- invoke void @f()
- to label %right.ret unwind label %inner
-right.ret:
- catchret %r to label %exit
-right.end:
- catchendpad unwind to caller
-shared:
- call void @h(i32 0)
- unreachable
-inner:
- %i = catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 1)
- catchret %i to label %shared
-inner.end:
- catchendpad unwind label %left.end
-exit:
- ret void
-}
-; This case tests the scenario where a funclet with multiple parents uses a
-; catchret to return to a block that may exist in either parent funclets.
-; Both %left and %right are parents of %inner. During common block cloning
-; a clone of %shared will be made so that both %left and %right have a copy,
-; but the copy of %shared for one of the parent funclets will be unreachable
-; until the %inner funclet is cloned. When the %inner.catch block is cloned
-; during the %inner funclet cloning, the catchret instruction should be updated
-; so that the catchret in the copy %inner.catch for %left returns to the copy of
-; %shared in %left and the catchret in the copy of %inner.catch for %right
-; returns to the copy of %shared for %right.
-; CHECK-LABEL: define void @test13(
-; CHECK: left:
-; CHECK: %l = catchpad []
-; CHECK: to label %left.cont unwind label %left.end
-; CHECK: left.cont:
-; CHECK: invoke void @f()
-; CHECK: to label %left.ret unwind label %[[INNER_LEFT:.+]]
-; CHECK: left.ret:
-; CHECK: catchret %l to label %invoke.cont
-; CHECK: left.end:
-; CHECK: catchendpad unwind to caller
-; CHECK: right:
-; CHECK: %r = catchpad []
-; CHECK: to label %right.catch unwind label %right.end
-; CHECK: right.catch:
-; CHECK: invoke void @f()
-; CHECK: to label %right.ret unwind label %[[INNER_RIGHT:.+]]
-; CHECK: right.ret:
-; CHECK: catchret %r to label %exit
-; CHECK: right.end:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[SHARED_RIGHT:.+]]:
-; CHECK: call void @h(i32 0)
-; CHECK: unreachable
-; CHECK: [[SHARED_LEFT:.+]]:
-; CHECK: call void @h(i32 0)
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: %[[I_RIGHT:.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: %[[I_LEFT:.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: call void @h(i32 1)
-; CHECK: catchret %[[I_RIGHT]] to label %[[SHARED_RIGHT]]
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: call void @h(i32 1)
-; CHECK: catchret %[[I_LEFT]] to label %[[SHARED_LEFT]]
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind label %[[LEFT_END]]
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind to caller
-
-
-define void @test14() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %exit unwind label %left
-left:
- %l = catchpad []
- to label %shared unwind label %left.end
-left.cont:
- invoke void @f()
- to label %left.ret unwind label %right
-left.ret:
- catchret %l to label %exit
-left.end:
- catchendpad unwind to caller
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind label %left.end
-shared:
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- %i = catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 0)
- catchret %i to label %left.cont
-inner.end:
- catchendpad unwind label %left.end
-exit:
- ret void
-}
-; This case tests another scenario where a funclet with multiple parents uses a
-; catchret to return to a block in one of the parent funclets. Here %right and
-; %left are both parents of %inner and %left is a parent of %right. The
-; catchret in %inner.catch will cause %left.cont and %left.ret to be cloned for
-; both %left and %right, but the catchret in %left.ret is invalid for %right
-; but the catchret instruction in the copy of %left.ret for %right will be
-; removed as an implausible terminator.
-; CHECK-LABEL: define void @test14(
-; CHECK: left:
-; CHECK: %l = catchpad []
-; CHECK: to label %[[SHARED_LEFT:.+]] unwind label %[[LEFT_END:.+]]
-; CHECK: [[LEFT_CONT:left.cont.*]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[LEFT_RET:.+]] unwind label %[[RIGHT:.+]]
-; CHECK: [[LEFT_RET]]:
-; CHECK: catchret %l to label %exit
-; CHECK: [[LEFT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[RIGHT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[RIGHT_CATCH:.+]] unwind label %[[RIGHT_END:.+]]
-; CHECK: [[RIGHT_CATCH]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind label %[[LEFT_END]]
-; CHECK: [[SHARED_LEFT]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_LEFT]]:
-; CHECK: [[I_LEFT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: [[I_RIGHT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: call void @h(i32 0)
-; CHECK: catchret [[I_LEFT]] to label %[[LEFT_CONT]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: call void @h(i32 0)
-; CHECK: unreachable
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind label %[[LEFT_END]]
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind to caller
-
-define void @test15() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %exit unwind label %left
-left:
- %l = catchpad []
- to label %left.catch unwind label %left.end
-left.catch:
- invoke void @f()
- to label %shared unwind label %right
-left.ret:
- catchret %l to label %exit
-left.end:
- catchendpad unwind to caller
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind label %left.end
-shared:
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- %i = catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 0)
- catchret %i to label %left.ret
-inner.end:
- catchendpad unwind label %left.end
-exit:
- ret void
-}
-; This case is a variation of test14 but instead of returning to an invoke the
-; catchret in %inner.catch returns to a catchret instruction.
-; CHECK-LABEL: define void @test15(
-; CHECK: left:
-; CHECK: %l = catchpad []
-; CHECK: to label %left.catch unwind label %[[LEFT_END:.+]]
-; CHECK: left.catch:
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_LEFT:.+]] unwind label %[[RIGHT:.+]]
-; CHECK: [[LEFT_RET_RIGHT:.+]]:
-; CHECK: unreachable
-; CHECK: [[LEFT_RET_LEFT:.+]]:
-; CHECK: catchret %l to label %exit
-; CHECK: [[LEFT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[RIGHT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[RIGHT_CATCH:.+]] unwind label %[[RIGHT_END:.+]]
-; CHECK: [[RIGHT_CATCH]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind label %[[LEFT_END]]
-; CHECK: [[SHARED_LEFT]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_LEFT]]:
-; CHECK: [[I_LEFT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: [[I_RIGHT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: call void @h(i32 0)
-; CHECK: catchret [[I_LEFT]] to label %[[LEFT_RET_LEFT]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: call void @h(i32 0)
-; CHECK: catchret [[I_RIGHT]] to label %[[LEFT_RET_RIGHT]]
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind label %[[LEFT_END]]
-
-
-define void @test16() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %exit unwind label %left
-left:
- %l = cleanuppad []
- br label %shared
-left.cont:
- cleanupret %l unwind label %right
-left.end:
- cleanupendpad %l unwind label %right
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- %i = catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 0)
- catchret %i to label %left.cont
-inner.end:
- catchendpad unwind label %left.end
-exit:
- ret void
-}
-; This case is another variation of test14 but here the catchret in %inner.catch
-; returns to a cleanupret instruction.
-; CHECK-LABEL: define void @test16(
-; CHECK: left:
-; CHECK: %l = cleanuppad []
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: [[LEFT_CONT_RIGHT:.+]]:
-; CHECK: unreachable
-; CHECK: [[LEFT_CONT_LEFT:.+]]:
-; CHECK: cleanupret %l unwind label %[[RIGHT:.+]]
-; CHECK: [[LEFT_END_LEFT:.+]]:
-; CHECK: cleanupendpad %l unwind label %[[RIGHT]]
-; CHECK: [[RIGHT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[RIGHT_CATCH:.+]] unwind label %[[RIGHT_END:.+]]
-; CHECK: [[RIGHT_CATCH]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: [[I_RIGHT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: [[I_LEFT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: call void @h(i32 0)
-; CHECK: catchret [[I_RIGHT]] to label %[[LEFT_CONT_RIGHT]]
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: call void @h(i32 0)
-; CHECK: catchret [[I_LEFT]] to label %[[LEFT_CONT_LEFT]]
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind label %[[LEFT_END_LEFT]]
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind to caller
-
-
-define void @test17() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %invoke.cont unwind label %left
-invoke.cont:
- invoke void @f()
- to label %exit unwind label %right
-left:
- %l = cleanuppad []
- br label %shared
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- invoke void @f()
- to label %unreachable unwind label %inner
-unreachable:
- unreachable
-inner:
- %i = catchpad []
- to label %inner.catch unwind label %inner.sibling
-inner.catch:
- call void @h(i32 0)
- unreachable
-inner.sibling:
- %is = catchpad []
- to label %inner.sibling.catch unwind label %inner.end
-inner.sibling.catch:
- invoke void @f()
- to label %unreachable unwind label %inner.end
-inner.end:
- catchendpad unwind label %right.end
-exit:
- ret void
-}
-; This case tests the scenario where two catchpads with the same catchendpad
-; have multiple parents. Both %left and %right are parents of %inner and
-; %inner.sibling so both of the inner funclets must be cloned. Because
-; the catchendpad in %inner.end unwinds to the catchendpad for %right, the
-; unwind edge should be removed for the copy of %inner.end that is reached
-; from %left. In addition, the %inner.siblin.catch block contains an invoke
-; that unwinds to the shared inner catchendpad. The unwind destination for
-; this invoke should be updated to unwind to the correct cloned %inner.end
-; for each path to the funclet.
-; CHECK-LABEL: define void @test17(
-; CHECK: left:
-; CHECK: %l = cleanuppad []
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: catchpad []
-; CHECK: to label %[[RIGHT_CATCH:.+]] unwind label %[[RIGHT_END:.+]]
-; CHECK: [[RIGHT_CATCH]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: [[I_RIGHT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_SIBLING_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: [[I_LEFT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_SIBLING_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: call void @h(i32 0)
-; CHECK: unreachable
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: call void @h(i32 0)
-; CHECK: unreachable
-; CHECK: [[INNER_SIBLING_RIGHT]]:
-; CHECK: [[IS_RIGHT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_SIBLING_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_SIBLING_LEFT]]:
-; CHECK: [[IS_LEFT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_SIBLING_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_SIBLING_CATCH_RIGHT]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[INNER_END_RIGHT]]
-; CHECK: [[INNER_SIBLING_CATCH_LEFT]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_END_LEFT]]
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind label %[[RIGHT_END]]
-
-
-define void @test18() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %invoke.cont unwind label %left
-invoke.cont:
- invoke void @f()
- to label %exit unwind label %right
-left:
- %l = cleanuppad []
- br label %shared
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- invoke void @f()
- to label %unreachable unwind label %inner
-unreachable:
- unreachable
-inner:
- %i = catchpad []
- to label %inner.catch unwind label %inner.sibling
-inner.catch:
- invoke void @f()
- to label %unreachable unwind label %inner.end
-inner.sibling:
- %is = catchpad []
- to label %inner.sibling.catch unwind label %inner.end
-inner.sibling.catch:
- call void @h(i32 0)
- unreachable
-inner.end:
- catchendpad unwind label %right.end
-exit:
- ret void
-}
-; This is like test17 except that the inner invoke is moved from the
-; %inner.sibling funclet to %inner so that it is unwinding to a
-; catchendpad block that has not yet been cloned. The unwind destination
-; of the invoke should still be updated to reach the correct copy of
-; %inner.end for the path by which it is reached.
-; CHECK-LABEL: define void @test18(
-; CHECK: left:
-; CHECK: %l = cleanuppad []
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: catchpad []
-; CHECK: to label %[[RIGHT_CATCH:.+]] unwind label %[[RIGHT_END:.+]]
-; CHECK: [[RIGHT_CATCH]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: [[I_RIGHT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_SIBLING_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: [[I_LEFT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_SIBLING_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_SIBLING_RIGHT]]:
-; CHECK: [[IS_RIGHT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_SIBLING_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT]]
-; CHECK: [[INNER_SIBLING_LEFT]]:
-; CHECK: [[IS_LEFT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_SIBLING_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT]]
-; CHECK: [[INNER_SIBLING_CATCH_RIGHT]]:
-; CHECK: call void @h(i32 0)
-; CHECK: unreachable
-; CHECK: [[INNER_SIBLING_CATCH_LEFT]]:
-; CHECK: call void @h(i32 0)
-; CHECK: unreachable
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind label %[[RIGHT_END]]
-
-
-define void @test19() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %invoke.cont unwind label %left
-invoke.cont:
- invoke void @f()
- to label %exit unwind label %right
-left:
- %l = cleanuppad []
- br label %shared
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- invoke void @f()
- to label %unreachable unwind label %inner
-unreachable:
- unreachable
-inner:
- %i = cleanuppad []
- invoke void @f()
- to label %unreachable unwind label %inner.end
-inner.end:
- cleanupendpad %i unwind label %right.end
-exit:
- ret void
-}
-; This case tests the scenario where an invoke in a funclet with multiple
-; parents unwinds to a cleanup end pad for the funclet. The unwind destination
-; for the invoke should map to the correct copy of the cleanup end pad block.
-; CHECK-LABEL: define void @test19(
-; CHECK: left:
-; CHECK: %l = cleanuppad []
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: catchpad []
-; CHECK: to label %[[RIGHT_CATCH:.+]] unwind label %[[RIGHT_END:.+]]
-; CHECK: [[RIGHT_CATCH]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: [[I_RIGHT:\%.+]] = cleanuppad []
-; CHECK: invoke void @f()
-; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: [[I_LEFT:\%.+]] = cleanuppad []
-; CHECK: invoke void @f()
-; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: cleanupendpad [[I_RIGHT]] unwind label %[[RIGHT_END]]
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: cleanupendpad [[I_LEFT]] unwind to caller
-
-define void @test20() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %invoke.cont unwind label %left
-invoke.cont:
- invoke void @f()
- to label %exit unwind label %right
-left:
- %l = cleanuppad []
- br label %shared
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- invoke void @f()
- to label %unreachable unwind label %inner
-unreachable:
- unreachable
-inner:
- %i = cleanuppad []
- invoke void @f()
- to label %unreachable unwind label %inner.cleanup
-inner.cleanup:
- cleanuppad []
- call void @f()
- unreachable
-exit:
- ret void
-}
-; This tests the case where a funclet with multiple parents contains an invoke
-; instruction that unwinds to a child funclet. Here %left and %right are both
-; parents of %inner. Initially %inner is the only parent of %inner.cleanup but
-; after %inner is cloned, %inner.cleanup has multiple parents and so it must
-; also be cloned.
-; CHECK-LABEL: define void @test20(
-; CHECK: left:
-; CHECK: %l = cleanuppad []
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: catchpad []
-; CHECK: to label %[[RIGHT_CATCH:.+]] unwind label %[[RIGHT_END:.+]]
-; CHECK: [[RIGHT_CATCH]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: [[I_RIGHT:\%.+]] = cleanuppad []
-; CHECK: invoke void @f()
-; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[INNER_CLEANUP_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: [[I_LEFT:\%.+]] = cleanuppad []
-; CHECK: invoke void @f()
-; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_CLEANUP_LEFT:.+]]
-; CHECK: [[INNER_CLEANUP_RIGHT]]:
-; CHECK: cleanuppad []
-; CHECK: call void @f()
-; CHECK: unreachable
-; CHECK: [[INNER_CLEANUP_LEFT]]:
-; CHECK: cleanuppad []
-; CHECK: call void @f()
-; CHECK: unreachable
-
-
diff --git a/test/CodeGen/WinEH/wineh-no-demotion.ll b/test/CodeGen/WinEH/wineh-no-demotion.ll
index 4f023947caa..7d18238c003 100644
--- a/test/CodeGen/WinEH/wineh-no-demotion.ll
+++ b/test/CodeGen/WinEH/wineh-no-demotion.ll
@@ -2,6 +2,8 @@
declare i32 @__CxxFrameHandler3(...)
+declare i32 @__C_specific_handler(...)
+
declare void @f()
declare i32 @g()
@@ -9,7 +11,7 @@ declare i32 @g()
declare void @h(i32)
; CHECK-LABEL: @test1(
-define void @test1() personality i32 (...)* @__CxxFrameHandler3 {
+define void @test1() personality i32 (...)* @__C_specific_handler {
entry:
invoke void @f()
to label %invoke.cont1 unwind label %left
@@ -23,11 +25,11 @@ invoke.cont2:
to label %exit unwind label %inner
left:
- %0 = cleanuppad []
+ %0 = cleanuppad within none []
br label %shared
right:
- %1 = cleanuppad []
+ %1 = cleanuppad within none []
br label %shared
shared:
@@ -40,25 +42,20 @@ shared.cont:
inner:
%phi = phi i32 [ %x, %shared ], [ 0, %invoke.cont2 ]
- %i = cleanuppad []
+ %i = cleanuppad within none []
call void @h(i32 %phi)
unreachable
-; CHECK [[INNER_INVOKE_CONT2:inner.*]]:
- ; CHECK: call void @h(i32 0)
-
-; CHECK [[INNER_RIGHT:inner.*]]:
- ; CHECK: call void @h(i32 %x)
-
-; CHECK [[INNER_LEFT:inner.*]]:
- ; CHECK: call void @h(i32 %x.for.left)
+; CHECK: %phi = phi i32 [ %x, %right ], [ 0, %invoke.cont2 ], [ %x.for.left, %left ]
+; CHECK: %i = cleanuppad within none []
+; CHECK: call void @h(i32 %phi)
exit:
unreachable
}
; CHECK-LABEL: @test2(
-define void @test2() personality i32 (...)* @__CxxFrameHandler3 {
+define void @test2() personality i32 (...)* @__C_specific_handler {
entry:
invoke void @f()
to label %invoke.cont unwind label %left
@@ -68,11 +65,11 @@ invoke.cont:
to label %exit unwind label %right
left:
- cleanuppad []
+ cleanuppad within none []
br label %shared
right:
- cleanuppad []
+ cleanuppad within none []
br label %shared
shared:
@@ -84,15 +81,13 @@ shared.cont:
unreachable
inner:
- %i = cleanuppad []
+ %i = cleanuppad within none []
call void @h(i32 %x)
unreachable
-; CHECK [[INNER_RIGHT:inner.*]]:
- ; CHECK: call void @h(i32 %x)
-
-; CHECK [[INNER_LEFT:inner.*]]:
- ; CHECK: call void @h(i32 %x.for.left)
+; CHECK: %x1 = phi i32 [ %x.for.left, %left ], [ %x, %right ]
+; CHECK: %i = cleanuppad within none []
+; CHECK: call void @h(i32 %x1)
exit:
unreachable
@@ -108,10 +103,47 @@ invoke.cont:
ret void
terminate:
-; CHECK: cleanuppad []
+; CHECK: cleanuppad within none []
; CHECK: call void @__std_terminate()
; CHECK: unreachable
- terminatepad [void ()* @__std_terminate] unwind to caller
+ terminatepad within none [void ()* @__std_terminate] unwind to caller
+}
+
+; CHECK-LABEL: @test4(
+define void @test4(i1 %x) personality i32 (...)* @__CxxFrameHandler3 {
+entry:
+ invoke void @f()
+ to label %invoke.cont1 unwind label %left
+
+invoke.cont1:
+ invoke void @f()
+ to label %exit unwind label %right
+
+left:
+ %0 = cleanuppad within none []
+ br label %shared
+
+right:
+ %1 = cleanuppad within none []
+ br i1 %x, label %shared, label %right.other
+
+right.other:
+ br label %shared
+
+shared:
+ %phi = phi i32 [ 1, %left ], [ 0, %right ], [ -1, %right.other ]
+ call void @h(i32 %phi)
+ unreachable
+
+; CHECK: %0 = cleanuppad within none []
+; CHECK: call void @h(i32 1)
+
+; CHECK: %1 = cleanuppad within none []
+; CHECK: %phi = phi i32 [ 0, %right ], [ -1, %right.other ]
+; CHECK: call void @h(i32 %phi)
+
+exit:
+ unreachable
}
declare void @__std_terminate()
diff --git a/test/CodeGen/WinEH/wineh-statenumbering-cleanups.ll b/test/CodeGen/WinEH/wineh-statenumbering-cleanups.ll
index bd1f2322878..f5889f03965 100644
--- a/test/CodeGen/WinEH/wineh-statenumbering-cleanups.ll
+++ b/test/CodeGen/WinEH/wineh-statenumbering-cleanups.ll
@@ -7,38 +7,6 @@ declare void @dummy_filter()
declare void @f(i32)
-; CHECK-LABEL: define void @test1(
-;Cxx: define void @test1() personality i32 (...)* @__CxxFrameHandler3 {
-;SEH: define void @test1() personality i32 (...)* @_except_handler3 {
-entry:
- ; CHECK: entry:
- ; CHECK: store i32 0
- ; CHECK: invoke void @f(i32 0)
- invoke void @f(i32 0)
- to label %exit unwind label %cleanup.pad
-cleanup.pad:
- ; CHECK: cleanup.pad:
- ; CHECK: store i32 1
- ; CHECK: invoke void @f(i32 1)
- %cleanup = cleanuppad []
- invoke void @f(i32 1)
- to label %cleanup.ret unwind label %catch.pad
-catch.pad:
-;Cxx: %catch = catchpad [i8* null, i32 u0x40, i8* null]
-;SEH: %catch = catchpad [void ()* @dummy_filter]
- to label %catch.body unwind label %catch.end
-catch.body:
- catchret %catch to label %cleanup.ret
-catch.end:
- catchendpad unwind label %cleanup.end
-cleanup.ret:
- cleanupret %cleanup unwind to caller
-cleanup.end:
- cleanupendpad %cleanup unwind to caller
-exit:
- ret void
-}
-
; CHECK-LABEL: define void @test2(
;Cxx: define void @test2(i1 %b) personality i32 (...)* @__CxxFrameHandler3 {
;SEH: define void @test2(i1 %b) personality i32 (...)* @_except_handler3 {
@@ -49,20 +17,18 @@ entry:
invoke void @f(i32 1)
to label %exit unwind label %cleanup.pad
cleanup.pad:
- %cleanup = cleanuppad []
+ %cleanup = cleanuppad within none []
br i1 %b, label %left, label %right
left:
- cleanupret %cleanup unwind label %catch.pad
+ cleanupret from %cleanup unwind label %catch.pad
right:
- cleanupret %cleanup unwind label %catch.pad
+ cleanupret from %cleanup unwind label %catch.pad
catch.pad:
-;Cxx: %catch = catchpad [i8* null, i32 u0x40, i8* null]
-;SEH: %catch = catchpad [void ()* @dummy_filter]
- to label %catch.body unwind label %catch.end
+ %cs1 = catchswitch within none [label %catch.body] unwind to caller
catch.body:
- catchret %catch to label %exit
-catch.end:
- catchendpad unwind to caller
+;Cxx: %catch = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
+;SEH: %catch = catchpad within %cs1 [void ()* @dummy_filter]
+ catchret from %catch to label %exit
exit:
ret void
}
@@ -72,29 +38,25 @@ exit:
;SEH: define void @test3() personality i32 (...)* @_except_handler3 {
entry:
; CHECK: entry:
- ; CHECK: store i32 1
+ ; CHECK: store i32 0
; CHECK: invoke void @f(i32 1)
invoke void @f(i32 1)
to label %exit unwind label %cleanup.pad
cleanup.pad:
; CHECK: cleanup.pad:
- ; CHECK: store i32 0
+ ; CHECK: store i32 1
; CHECK: invoke void @f(i32 0)
- %cleanup = cleanuppad []
+ %cleanup = cleanuppad within none []
invoke void @f(i32 0)
- to label %unreachable unwind label %cleanup.end
+ to label %unreachable unwind label %catch.pad
unreachable:
unreachable
-cleanup.end:
- cleanupendpad %cleanup unwind label %catch.pad
catch.pad:
-;Cxx: %catch = catchpad [i8* null, i32 u0x40, i8* null]
-;SEH: %catch = catchpad [void ()* @dummy_filter]
- to label %catch.body unwind label %catch.end
+ %cs1 = catchswitch within none [label %catch.body] unwind to caller
catch.body:
- catchret %catch to label %exit
-catch.end:
- catchendpad unwind to caller
+;Cxx: %catch = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
+;SEH: %catch = catchpad within %cs1 [void ()* @dummy_filter]
+ catchret from %catch to label %exit
exit:
ret void
}
diff --git a/test/CodeGen/WinEH/wineh-statenumbering.ll b/test/CodeGen/WinEH/wineh-statenumbering.ll
index 2d5f7ca0c0e..b7ec843aa39 100644
--- a/test/CodeGen/WinEH/wineh-statenumbering.ll
+++ b/test/CodeGen/WinEH/wineh-statenumbering.ll
@@ -37,9 +37,10 @@ entry:
to label %unreachable.for.entry unwind label %catch.dispatch
catch.dispatch: ; preds = %entry
- %1 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock
+ %cs1 = catchswitch within none [label %catch] unwind to caller
catch: ; preds = %catch.dispatch
+ %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
; CHECK: catch:
; CHECK: store i32 2
; CHECK: invoke void @_CxxThrowException(
@@ -47,34 +48,22 @@ catch: ; preds = %catch.dispatch
to label %unreachable unwind label %catch.dispatch.1
catch.dispatch.1: ; preds = %catch
- %2 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch.3 unwind label %catchendblock.2
-
+ %cs2 = catchswitch within %1 [label %catch.3] unwind to caller
catch.3: ; preds = %catch.dispatch.1
+ %2 = catchpad within %cs2 [i8* null, i32 u0x40, i8* null]
; CHECK: catch.3:
; CHECK: store i32 3
- ; CHECK: invoke void @g(i32 1)
- invoke void @g(i32 1)
- to label %invoke.cont unwind label %catchendblock.2
-
-invoke.cont: ; preds = %catch.3
- catchret %2 to label %try.cont
+ ; CHECK: call void @g(i32 1)
+ call void @g(i32 1)
+ catchret from %2 to label %try.cont
-try.cont: ; preds = %invoke.cont
+try.cont: ; preds = %catch.3
; CHECK: try.cont:
; CHECK: store i32 1
- ; CHECK: invoke void @g(i32 2)
- invoke void @g(i32 2)
- to label %invoke.cont.4 unwind label %catchendblock
-
-invoke.cont.4: ; preds = %try.cont
+ ; CHECK: call void @g(i32 2)
+ call void @g(i32 2)
unreachable
-catchendblock.2: ; preds = %catch.3, %catch.dispatch.1
- catchendpad unwind label %catchendblock
-
-catchendblock: ; preds = %catchendblock.2, %try.cont, %catch.dispatch
- catchendpad unwind to caller
-
unreachable: ; preds = %catch
unreachable
diff --git a/test/CodeGen/X86/branchfolding-catchpads.ll b/test/CodeGen/X86/branchfolding-catchpads.ll
index 21c7818e519..0468b3c314f 100644
--- a/test/CodeGen/X86/branchfolding-catchpads.ll
+++ b/test/CodeGen/X86/branchfolding-catchpads.ll
@@ -19,24 +19,18 @@ if.else:
to label %cleanup unwind label %catch.dispatch
catch.dispatch:
- catchpad [i8* null, i32 8, i8* null]
- to label %catch unwind label %catch.dispatch.2
+ %cs = catchswitch within none [ label %catch, label %catch.2 ] unwind to caller
catch:
- invoke void @throw() noreturn
- to label %unreachable unwind label %catchendblock
-
-catch.dispatch.2:
- catchpad [i8* null, i32 64, i8* null]
- to label %catch.2 unwind label %catchendblock
+ catchpad within %cs [i8* null, i32 8, i8* null]
+ call void @throw() noreturn
+ br label %unreachable
catch.2:
+ catchpad within %cs [i8* null, i32 64, i8* null]
store i8 1, i8* %b
- invoke void @throw() noreturn
- to label %unreachable unwind label %catchendblock
-
-catchendblock:
- catchendpad unwind to caller
+ call void @throw() noreturn
+ br label %unreachable
cleanup:
%retval = phi i16 [ %call1, %if.then ], [ %call2, %if.else ]
@@ -67,31 +61,22 @@ if.else:
to label %cleanup unwind label %catch.dispatch
catch.dispatch:
- catchpad [i8* null, i32 8, i8* null]
- to label %catch unwind label %catch.dispatch.2
+ %cs = catchswitch within none [ label %catch, label %catch.2, label %catch.3 ] unwind to caller
catch:
- invoke void @throw() noreturn
- to label %unreachable unwind label %catchendblock
-
-catch.dispatch.2:
- %c2 = catchpad [i8* null, i32 32, i8* null]
- to label %catch.2 unwind label %catch.dispatch.3
+ catchpad within %cs [i8* null, i32 8, i8* null]
+ call void @throw() noreturn
+ br label %unreachable
catch.2:
+ %c2 = catchpad within %cs [i8* null, i32 32, i8* null]
store i8 1, i8* %b
- catchret %c2 to label %cleanup
-
-catch.dispatch.3:
- %c3 = catchpad [i8* null, i32 64, i8* null]
- to label %catch.3 unwind label %catchendblock
+ catchret from %c2 to label %cleanup
catch.3:
+ %c3 = catchpad within %cs [i8* null, i32 64, i8* null]
store i8 2, i8* %b
- catchret %c3 to label %cleanup
-
-catchendblock:
- catchendpad unwind to caller
+ catchret from %c3 to label %cleanup
cleanup:
%retval = phi i16 [ %call1, %if.then ], [ %call2, %if.else ], [ -1, %catch.2 ], [ -1, %catch.3 ]
diff --git a/test/CodeGen/X86/catchpad-realign-savexmm.ll b/test/CodeGen/X86/catchpad-realign-savexmm.ll
index 267c69332c3..1160101792f 100644
--- a/test/CodeGen/X86/catchpad-realign-savexmm.ll
+++ b/test/CodeGen/X86/catchpad-realign-savexmm.ll
@@ -14,19 +14,17 @@ define void @f() personality i32 (...)* @__CxxFrameHandler3 {
%v1 = fadd double %v, 1.0
store double %v1, double* @fp_global
invoke void @g()
- to label %return unwind label %catch
+ to label %return unwind label %catch.dispatch
return:
ret void
-catch:
- %p = catchpad [i8* null, i32 64, i8* null]
- to label %catchit unwind label %endpad
+catch.dispatch:
+ %cs1 = catchswitch within none [label %catch] unwind to caller
-catchit:
- catchret %p to label %return
-endpad:
- catchendpad unwind to caller
+catch:
+ %p = catchpad within %cs1 [i8* null, i32 64, i8* null]
+ catchret from %p to label %return
}
; CHECK: f: # @f
diff --git a/test/CodeGen/X86/catchpad-regmask.ll b/test/CodeGen/X86/catchpad-regmask.ll
index fe3a238e173..0d436f6eb59 100644
--- a/test/CodeGen/X86/catchpad-regmask.ll
+++ b/test/CodeGen/X86/catchpad-regmask.ll
@@ -41,14 +41,14 @@ entry:
to label %unreachable unwind label %catch.dispatch
catch.dispatch: ; preds = %entry
- %0 = catchpad [i8* null, i32 64, i8* null]
- to label %catch unwind label %catchendblock
+ %cs1 = catchswitch within none [label %catch] unwind to caller
catch: ; preds = %catch.dispatch
+ %0 = catchpad within %cs1 [i8* null, i32 64, i8* null]
%idxprom1 = sext i32 %idx2 to i64
%arrayidx2 = getelementptr inbounds [4 x i32], [4 x i32]* @array, i64 0, i64 %idxprom1
store i32 222, i32* %arrayidx2, align 4, !tbaa !2
- catchret %0 to label %try.cont
+ catchret from %0 to label %try.cont
try.cont: ; preds = %catch
%idxprom3 = sext i32 %idx3 to i64
@@ -56,9 +56,6 @@ try.cont: ; preds = %catch
store i32 333, i32* %arrayidx4, align 4, !tbaa !2
ret void
-catchendblock: ; preds = %catch.dispatch
- catchendpad unwind to caller
-
unreachable: ; preds = %entry
unreachable
}
@@ -98,20 +95,17 @@ entry:
to label %unreachable unwind label %catch.dispatch
catch.dispatch: ; preds = %entry
- %0 = catchpad [i8* null, i32 64, i8* null]
- to label %catch unwind label %catchendblock
+ %cs1 = catchswitch within none [label %catch] unwind to caller
catch: ; preds = %catch.dispatch
+ %0 = catchpad within %cs1 [i8* null, i32 64, i8* null]
store i32 222, i32* @imported, align 4, !tbaa !2
- catchret %0 to label %try.cont
+ catchret from %0 to label %try.cont
try.cont: ; preds = %catch
store i32 333, i32* @imported, align 4, !tbaa !2
ret void
-catchendblock: ; preds = %catch.dispatch
- catchendpad unwind to caller
-
unreachable: ; preds = %entry
unreachable
}
diff --git a/test/CodeGen/X86/catchpad-weight.ll b/test/CodeGen/X86/catchpad-weight.ll
index e8b416845ec..1abcd03ac64 100644
--- a/test/CodeGen/X86/catchpad-weight.ll
+++ b/test/CodeGen/X86/catchpad-weight.ll
@@ -2,7 +2,7 @@
; Check if the edge weight to the catchpad is calculated correctly.
-; CHECK: Successors according to CFG: BB#3(0x7ffff100 / 0x80000000 = 100.00%) BB#1(0x00000800 / 0x80000000 = 0.00%) BB#4(0x00000400 / 0x80000000 = 0.00%) BB#6(0x00000200 / 0x80000000 = 0.00%) BB#8(0x00000100 / 0x80000000 = 0.00%)
+; CHECK: Successors according to CFG: BB#2(0x7ffff100 / 0x80000000 = 100.00%) BB#1(0x00000800 / 0x80000000 = 0.00%) BB#3(0x00000400 / 0x80000000 = 0.00%) BB#4(0x00000200 / 0x80000000 = 0.00%) BB#5(0x00000100 / 0x80000000 = 0.00%)
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64--windows-msvc18.0.0"
@@ -31,11 +31,11 @@ entry:
to label %try.cont unwind label %catch.dispatch
catch.dispatch: ; preds = %entry
- %1 = catchpad [%rtti.TypeDescriptor7* @"\01??_R0?AUA@@@8", i32 0, i8* null]
- to label %catch.5 unwind label %catch.dispatch.1
+ %cs1 = catchswitch within none [label %catch.5] unwind label %catch.dispatch.1
catch.5: ; preds = %catch.dispatch
- catchret %1 to label %try.cont
+ %1 = catchpad within %cs1 [%rtti.TypeDescriptor7* @"\01??_R0?AUA@@@8", i32 0, i8* null]
+ catchret from %1 to label %try.cont
try.cont: ; preds = %entry, %catch, %catch.3, %catch.5
call void @"\01??1HasDtor@@QEAA@XZ"(%struct.HasDtor* nonnull %o) #4
@@ -43,26 +43,23 @@ try.cont: ; preds = %entry, %catch, %cat
ret i32 0
catch.dispatch.1: ; preds = %catch.dispatch
- %2 = catchpad [%rtti.TypeDescriptor7* @"\01??_R0?AUB@@@8", i32 0, i8* null]
- to label %catch.3 unwind label %catch.dispatch.2
+ %cs2 = catchswitch within none [label %catch.3] unwind label %catch.dispatch.2
catch.3: ; preds = %catch.dispatch.1
- catchret %2 to label %try.cont
+ %2 = catchpad within %cs2 [%rtti.TypeDescriptor7* @"\01??_R0?AUB@@@8", i32 0, i8* null]
+ catchret from %2 to label %try.cont
catch.dispatch.2: ; preds = %catch.dispatch.1
- %3 = catchpad [%rtti.TypeDescriptor7* @"\01??_R0?AUC@@@8", i32 0, i8* null]
- to label %catch unwind label %catchendblock
+ %cs3 = catchswitch within none [label %catch] unwind label %ehcleanup
catch: ; preds = %catch.dispatch.2
- catchret %3 to label %try.cont
-
-catchendblock: ; preds = %catch.dispatch.2
- catchendpad unwind label %ehcleanup
+ %3 = catchpad within %cs3 [%rtti.TypeDescriptor7* @"\01??_R0?AUC@@@8", i32 0, i8* null]
+ catchret from %3 to label %try.cont
ehcleanup: ; preds = %catchendblock
- %4 = cleanuppad []
+ %4 = cleanuppad within none []
call void @"\01??1HasDtor@@QEAA@XZ"(%struct.HasDtor* nonnull %o) #4
- cleanupret %4 unwind to caller
+ cleanupret from %4 unwind to caller
}
; Function Attrs: nounwind argmemonly
diff --git a/test/CodeGen/X86/catchret-empty-fallthrough.ll b/test/CodeGen/X86/catchret-empty-fallthrough.ll
index 3b3b3f5d091..585f7bc33e3 100644
--- a/test/CodeGen/X86/catchret-empty-fallthrough.ll
+++ b/test/CodeGen/X86/catchret-empty-fallthrough.ll
@@ -19,14 +19,11 @@ try: ; preds = %entry
to label %fallthrough unwind label %dispatch
dispatch: ; preds = %try
- %0 = catchpad [i8* null]
- to label %catch unwind label %catchendblock.i.i
+ %cs1 = catchswitch within none [label %catch] unwind to caller
catch: ; preds = %dispatch
- catchret %0 to label %return
-
-catchendblock.i.i: ; preds = %dispatch
- catchendpad unwind to caller
+ %0 = catchpad within %cs1 [i8* null]
+ catchret from %0 to label %return
fallthrough: ; preds = %try
unreachable
diff --git a/test/CodeGen/X86/catchret-fallthrough.ll b/test/CodeGen/X86/catchret-fallthrough.ll
index f732566d0cb..6a94b290e82 100644
--- a/test/CodeGen/X86/catchret-fallthrough.ll
+++ b/test/CodeGen/X86/catchret-fallthrough.ll
@@ -18,14 +18,11 @@ entry:
to label %invoke.cont.3 unwind label %catch.dispatch
catch.dispatch: ; preds = %entry
- %0 = catchpad [i8* null, i32 64, i8* null]
- to label %catch unwind label %catchendblock
+ %cs1 = catchswitch within none [label %catch] unwind to caller
catch: ; preds = %catch.dispatch
- catchret %0 to label %nrvo.skipdtor
-
-catchendblock: ; preds = %catch, %catch.dispatch
- catchendpad unwind to caller
+ %0 = catchpad within %cs1 [i8* null, i32 64, i8* null]
+ catchret from %0 to label %nrvo.skipdtor
invoke.cont.3: ; preds = %entry
store i32 123, i32* @some_global
diff --git a/test/CodeGen/X86/cleanuppad-inalloca.ll b/test/CodeGen/X86/cleanuppad-inalloca.ll
index 8858f3704a1..294ef3abc46 100644
--- a/test/CodeGen/X86/cleanuppad-inalloca.ll
+++ b/test/CodeGen/X86/cleanuppad-inalloca.ll
@@ -29,9 +29,9 @@ invoke.cont: ; preds = %entry
ret void
ehcleanup: ; preds = %entry
- %2 = cleanuppad []
+ %2 = cleanuppad within none []
call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %0)
- cleanupret %2 unwind to caller
+ cleanupret from %2 unwind to caller
}
; CHECK: _passes_two:
diff --git a/test/CodeGen/X86/cleanuppad-large-codemodel.ll b/test/CodeGen/X86/cleanuppad-large-codemodel.ll
index df866f9598a..e32cdbed73f 100644
--- a/test/CodeGen/X86/cleanuppad-large-codemodel.ll
+++ b/test/CodeGen/X86/cleanuppad-large-codemodel.ll
@@ -9,9 +9,9 @@ entry:
invoke void @bar()
to label %exit unwind label %cleanup
cleanup:
- %c = cleanuppad []
+ %c = cleanuppad within none []
call void @bar()
- cleanupret %c unwind to caller
+ cleanupret from %c unwind to caller
exit:
ret void
}
diff --git a/test/CodeGen/X86/cleanuppad-realign.ll b/test/CodeGen/X86/cleanuppad-realign.ll
index a19cf261307..d322932da4c 100644
--- a/test/CodeGen/X86/cleanuppad-realign.ll
+++ b/test/CodeGen/X86/cleanuppad-realign.ll
@@ -17,9 +17,9 @@ invoke.cont: ; preds = %entry
ret void
ehcleanup: ; preds = %entry
- %0 = cleanuppad []
+ %0 = cleanuppad within none []
call void @Dtor(i64* %o)
- cleanupret %0 unwind to caller
+ cleanupret from %0 unwind to caller
}
; X86-LABEL: _realigned_cleanup: # @realigned_cleanup
diff --git a/test/CodeGen/X86/funclet-layout.ll b/test/CodeGen/X86/funclet-layout.ll
index 053d484889b..b5972df43cc 100644
--- a/test/CodeGen/X86/funclet-layout.ll
+++ b/test/CodeGen/X86/funclet-layout.ll
@@ -15,21 +15,21 @@ entry:
to label %unreachable unwind label %catch.dispatch
catch.dispatch:
- %cp = catchpad [i8* null, i32 64, i8* null]
- to label %catch unwind label %catchendblock
+ %cs1 = catchswitch within none [label %catch] unwind to caller
catch:
- br i1 %B, label %catchret, label %catch
+ %cp = catchpad within %cs1 [i8* null, i32 64, i8* null]
+ br label %catch.loop
+
+catch.loop:
+ br i1 %B, label %catchret, label %catch.loop
catchret:
- catchret %cp to label %try.cont
+ catchret from %cp to label %try.cont
try.cont:
ret void
-catchendblock:
- catchendpad unwind to caller
-
unreachable:
unreachable
}
@@ -55,54 +55,50 @@ entry:
to label %unreachable unwind label %catch.dispatch
catch.dispatch: ; preds = %entry
- %0 = catchpad [i8* null, i32 64, i8* null]
- to label %catch unwind label %catchendblock
+ %cs1 = catchswitch within none [label %catch] unwind to caller
catch: ; preds = %catch.dispatch
+ %0 = catchpad within %cs1 [i8* null, i32 64, i8* null]
invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #1
to label %unreachable unwind label %catch.dispatch.1
catch.dispatch.1: ; preds = %catch
- %1 = catchpad [i8* null, i32 64, i8* null]
- to label %catch.3 unwind label %catchendblock.2
+ %cs2 = catchswitch within %0 [label %catch.3] unwind to caller
catch.3: ; preds = %catch.dispatch.1
- catchret %1 to label %try.cont
+ %1 = catchpad within %cs2 [i8* null, i32 64, i8* null]
+ catchret from %1 to label %try.cont
try.cont: ; preds = %catch.3
- catchret %0 to label %try.cont.5
+ catchret from %0 to label %try.cont.5
try.cont.5: ; preds = %try.cont
ret i32 0
-catchendblock.2: ; preds = %catch.dispatch.1
- catchendpad unwind label %catchendblock
-
-catchendblock: ; preds = %catchendblock.2, %catch.dispatch
- catchendpad unwind to caller
-
unreachable: ; preds = %catch, %entry
unreachable
-
}
; CHECK-LABEL: test2:
-; The entry funclet contains %entry and %try.cont.5
+; The parent function contains %entry and %try.cont.5
+; CHECK: .seh_proc
; CHECK: # %entry
; CHECK: # %try.cont.5
; CHECK: retq
-; The outer catch funclet contains %catch.dispatch
-; CHECK: # %catch.dispatch{{$}}
+; The inner catch funclet contains %catch.3
+; CHECK: .seh_proc
+; CHECK: # %catch.3{{$}}
+; CHECK: retq
+
+; The outer catch funclet contains %catch
+; CHECK: .seh_proc
+; CHECK: # %catch{{$}}
; CHECK: callq _CxxThrowException
; CHECK: # %unreachable
; CHECK: ud2
-; The inner catch funclet contains %catch.dispatch.1
-; CHECK: # %catch.dispatch.1
-; CHECK: retq
-
define void @test3(i1 %V) #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
@@ -110,24 +106,21 @@ entry:
to label %try.cont unwind label %catch.dispatch
catch.dispatch: ; preds = %entry
- %0 = catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
- to label %catch.2 unwind label %catch.dispatch.1
+ %cs1 = catchswitch within none [label %catch.2] unwind label %catch.dispatch.1
catch.2: ; preds = %catch.dispatch
+ %0 = catchpad within %cs1 [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
tail call void @exit(i32 0) #2
unreachable
catch.dispatch.1: ; preds = %catch.dispatch
- %1 = catchpad [i8* null, i32 64, i8* null]
- to label %catch unwind label %catchendblock
+ %cs2 = catchswitch within none [label %catch] unwind to caller
catch: ; preds = %catch.dispatch.1
+ %1 = catchpad within %cs2 [i8* null, i32 64, i8* null]
tail call void @exit(i32 0) #2
unreachable
-catchendblock: ; preds = %catch.dispatch.1
- catchendpad unwind to caller
-
try.cont: ; preds = %entry
br i1 %V, label %exit_one, label %exit_two
@@ -150,13 +143,13 @@ exit_two:
; CHECK-NOT: # exit_two
; CHECK: ud2
-; The catch(...) funclet contains %catch.dispatch
-; CHECK: # %catch.dispatch{{$}}
+; The catch(...) funclet contains %catch.2
+; CHECK: # %catch.2{{$}}
; CHECK: callq exit
; CHECK: ud2
-; The catch(int) funclet contains %catch.dispatch.1
-; CHECK: # %catch.dispatch.1
+; The catch(int) funclet contains %catch
+; CHECK: # %catch{{$}}
; CHECK: callq exit
; CHECK: ud2
diff --git a/test/CodeGen/X86/late-address-taken.ll b/test/CodeGen/X86/late-address-taken.ll
index 8f85393b67c..f98c53595ab 100644
--- a/test/CodeGen/X86/late-address-taken.ll
+++ b/test/CodeGen/X86/late-address-taken.ll
@@ -22,19 +22,17 @@ body:
invoke void @f()
to label %exit unwind label %catch.pad
catch.pad:
- %catch = catchpad [i32 33554467]
- to label %catch.body unwind label %catch.end
+ %cs1 = catchswitch within none [label %catch.body] unwind to caller
catch.body:
- catchret %catch to label %exit
-catch.end:
- catchendpad unwind to caller
+ %catch = catchpad within %cs1 [i32 33554467]
+ catchret from %catch to label %exit
exit:
ret void
}
; CHECK-LABEL: catchret: # @catchret
; CHECK: [[Exit:^[^ :]+]]: # Block address taken
; CHECK-NEXT: # %exit
-; CHECK: # %catch.pad
+; CHECK: # %catch.body
; CHECK: .seh_endprolog
; CHECK: leaq [[Exit]](%rip), %rax
; CHECK: retq # CATCHRET
diff --git a/test/CodeGen/X86/seh-catch-all-win32.ll b/test/CodeGen/X86/seh-catch-all-win32.ll
index 5d9d5038385..69afb1b9d9c 100644
--- a/test/CodeGen/X86/seh-catch-all-win32.ll
+++ b/test/CodeGen/X86/seh-catch-all-win32.ll
@@ -22,16 +22,13 @@ entry:
to label %__try.cont unwind label %lpad
lpad: ; preds = %entry
- %p = catchpad [i8* bitcast (i32 ()* @"filt$main" to i8*)]
- to label %__except unwind label %endpad
+ %cs1 = catchswitch within none [label %__except] unwind to caller
__except: ; preds = %lpad
+ %p = catchpad within %cs1 [i8* bitcast (i32 ()* @"filt$main" to i8*)]
%code = load i32, i32* %__exceptioncode, align 4
%call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @str, i32 0, i32 0), i32 %code) #4
- catchret %p to label %__try.cont
-
-endpad: ; preds = %lpad
- catchendpad unwind to caller
+ catchret from %p to label %__try.cont
__try.cont: ; preds = %entry, %__except
ret i32 0
@@ -73,7 +70,7 @@ entry:
; CHECK: popl %edi
; CHECK: popl %ebx
; CHECK: retl
-; CHECK: LBB0_[[lpbb:[0-9]+]]: # %lpad{{$}}
+; CHECK: LBB0_[[lpbb:[0-9]+]]: # %__except{{$}}
; stackrestore
; CHECK: movl -24(%ebp), %esp
; EH state -1
diff --git a/test/CodeGen/X86/seh-catch-all.ll b/test/CodeGen/X86/seh-catch-all.ll
index aa1b6e040ff..4463485f209 100644
--- a/test/CodeGen/X86/seh-catch-all.ll
+++ b/test/CodeGen/X86/seh-catch-all.ll
@@ -16,16 +16,13 @@ __try.cont:
ret i32 0
lpad:
- %p = catchpad [i8* null, i32 64, i8* null]
- to label %catchall unwind label %endpad
+ %cs1 = catchswitch within none [label %catchall] unwind to caller
catchall:
+ %p = catchpad within %cs1 [i8* null, i32 64, i8* null]
%code = call i32 @llvm.eh.exceptioncode(token %p)
call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @str, i64 0, i64 0), i32 %code)
- catchret %p to label %__try.cont
-
-endpad:
- catchendpad unwind to caller
+ catchret from %p to label %__try.cont
}
; Check that we can get the exception code from eax to the printf.
@@ -33,7 +30,7 @@ endpad:
; CHECK-LABEL: main:
; CHECK: callq crash
; CHECK: retq
-; CHECK: .LBB0_2: # %lpad
+; CHECK: .LBB0_2: # %catchall
; CHECK: leaq str(%rip), %rcx
; CHECK: movl %eax, %edx
; CHECK: callq printf
diff --git a/test/CodeGen/X86/seh-catchpad.ll b/test/CodeGen/X86/seh-catchpad.ll
index 895dba883ae..a8be4ec1450 100644
--- a/test/CodeGen/X86/seh-catchpad.ll
+++ b/test/CodeGen/X86/seh-catchpad.ll
@@ -45,13 +45,6 @@ entry:
%call = invoke i32 @do_div(i32 1, i32 0) #4
to label %__try.cont.12 unwind label %catch.dispatch
-catch.dispatch: ; preds = %entry
- %0 = catchpad [i8* null]
- to label %__except unwind label %catchendblock
-
-__except: ; preds = %catch.dispatch
- catchret %0 to label %__except.2
-
__except.2: ; preds = %__except
%call4 = invoke i32 @do_div(i32 1, i32 0) #4
to label %invoke.cont.3 unwind label %ehcleanup
@@ -60,24 +53,6 @@ invoke.cont.3: ; preds = %__except.2
invoke fastcc void @"\01?fin$0@0@main@@"() #4
to label %__try.cont.12 unwind label %catch.dispatch.7
-catchendblock: ; preds = %catch.dispatch
- catchendpad unwind label %catch.dispatch.7
-
-ehcleanup: ; preds = %__except.2
- %1 = cleanuppad []
- invoke fastcc void @"\01?fin$0@0@main@@"() #4
- to label %invoke.cont.6 unwind label %ehcleanup.end
-
-invoke.cont.6: ; preds = %ehcleanup
- cleanupret %1 unwind label %catch.dispatch.7
-
-catch.dispatch.7: ; preds = %invoke.cont.3, %invoke.cont.6, %ehcleanup.end, %catchendblock
- %2 = catchpad [i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@main@@" to i8*)]
- to label %__except.ret unwind label %catchendblock.8
-
-__except.ret: ; preds = %catch.dispatch.7
- catchret %2 to label %__except.9
-
__except.9: ; preds = %__except.ret
%call11 = tail call i32 @puts(i8* nonnull getelementptr inbounds ([7 x i8], [7 x i8]* @"\01??_C@_06IBDBCMGJ@caught?$AA@", i64 0, i64 0))
br label %__try.cont.12
@@ -85,11 +60,27 @@ __except.9: ; preds = %__except.ret
__try.cont.12: ; preds = %invoke.cont.3, %entry, %__except.9
ret i32 0
-catchendblock.8: ; preds = %catch.dispatch.7
- catchendpad unwind to caller
+catch.dispatch: ; preds = %entry
+ %cs1 = catchswitch within none [label %__except] unwind label %catch.dispatch.7
+
+__except: ; preds = %catch.dispatch
+ %cp1 = catchpad within %cs1 [i8* null]
+ catchret from %cp1 to label %__except.2
-ehcleanup.end: ; preds = %ehcleanup
- cleanupendpad %1 unwind label %catch.dispatch.7
+ehcleanup: ; preds = %__except.2
+ %cp2 = cleanuppad within none []
+ invoke fastcc void @"\01?fin$0@0@main@@"() #4
+ to label %invoke.cont.6 unwind label %catch.dispatch.7
+
+invoke.cont.6: ; preds = %ehcleanup
+ cleanupret from %cp2 unwind label %catch.dispatch.7
+
+catch.dispatch.7:
+ %cs2 = catchswitch within none [label %__except.ret] unwind to caller
+
+__except.ret: ; preds = %catch.dispatch.7
+ %cp3 = catchpad within %cs2 [i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@main@@" to i8*)]
+ catchret from %cp3 to label %__except.9
}
; CHECK: main: # @main
@@ -112,7 +103,7 @@ ehcleanup.end: ; preds = %ehcleanup
; CHECK: addq $32, %rsp
; CHECK: popq %rbp
; CHECK: retq
-; CHECK: .LBB1_[[except1bb:[0-9]+]]: # %catch.dispatch
+; CHECK: .LBB1_[[except1bb:[0-9]+]]: # %__except
; CHECK: .Ltmp2:
; CHECK: movl $1, %ecx
; CHECK: xorl %edx, %edx
@@ -120,7 +111,7 @@ ehcleanup.end: ; preds = %ehcleanup
; CHECK: .Ltmp3:
; CHECK: callq "?fin$0@0@main@@"
; CHECK: jmp .LBB1_[[epilogue]]
-; CHECK: .LBB1_[[except2bb:[0-9]+]]: # %catch.dispatch.7
+; CHECK: .LBB1_[[except2bb:[0-9]+]]: # %__except.ret
; CHECK: leaq "??_C@_06IBDBCMGJ@caught?$AA@"(%rip), %rcx
; CHECK: callq puts
; CHECK: jmp .LBB1_[[epilogue]]
@@ -143,18 +134,18 @@ ehcleanup.end: ; preds = %ehcleanup
; CHECK-NEXT: .long .Ltmp2@IMGREL+1
; CHECK-NEXT: .long .Ltmp3@IMGREL+1
; CHECK-NEXT: .long "?filt$0@0@main@@"@IMGREL
-; CHECK-NEXT: .long .LBB1_5@IMGREL
+; CHECK-NEXT: .long .LBB1_3@IMGREL
; CHECK-NEXT: .long .Ltmp6@IMGREL+1
; CHECK-NEXT: .long .Ltmp7@IMGREL+1
; CHECK-NEXT: .long "?filt$0@0@main@@"@IMGREL
-; CHECK-NEXT: .long .LBB1_5@IMGREL
+; CHECK-NEXT: .long .LBB1_3@IMGREL
; CHECK-NEXT: .Llsda_end0:
; CHECK: .text
; CHECK: .seh_endproc
-; CHECK: "?dtor$3@?0?main@4HA":
-; CHECK: .seh_proc "?dtor$3@?0?main@4HA"
+; CHECK: "?dtor$[[finbb]]@?0?main@4HA":
+; CHECK: .seh_proc "?dtor$[[finbb]]@?0?main@4HA"
; CHECK: .seh_handler __C_specific_handler, @unwind, @except
; CHECK: .LBB1_[[finbb]]: # %ehcleanup
; CHECK: movq %rdx, 16(%rsp)
diff --git a/test/CodeGen/X86/seh-except-finally.ll b/test/CodeGen/X86/seh-except-finally.ll
index 7acb802aa68..b252b5b1248 100644
--- a/test/CodeGen/X86/seh-except-finally.ll
+++ b/test/CodeGen/X86/seh-except-finally.ll
@@ -49,37 +49,24 @@ invoke.cont2: ; preds = %invoke.cont
br label %__try.cont
__finally: ; preds = %entry
- %cleanuppad = cleanuppad []
+ %cleanuppad = cleanuppad within none []
%locals = call i8* @llvm.localaddress()
invoke void @"\01?fin$0@0@use_both@@"(i1 zeroext true, i8* %locals) #5
- to label %invoke.cont3 unwind label %cleanupendpad
+ to label %invoke.cont3 unwind label %catch.dispatch
invoke.cont3: ; preds = %__finally
- cleanupret %cleanuppad unwind label %catch.dispatch
-
-cleanupendpad:
- cleanupendpad %cleanuppad unwind label %catch.dispatch
+ cleanupret from %cleanuppad unwind label %catch.dispatch
catch.dispatch: ; preds = %invoke.cont3, %lpad1
- %catchpad = catchpad [i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@use_both@@" to i8*)]
- to label %__except unwind label %catchendpad
+ %cs1 = catchswitch within none [label %__except] unwind to caller
__except: ; preds = %catch.dispatch
+ %catchpad = catchpad within %cs1 [i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@use_both@@" to i8*)]
%call = call i32 @puts(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @"\01??_C@_08MLCMLGHM@__except?$AA@", i32 0, i32 0))
- catchret %catchpad to label %__try.cont
-
-catchendpad:
- catchendpad unwind to caller
+ catchret from %catchpad to label %__try.cont
__try.cont: ; preds = %__except, %invoke.cont2
ret void
-
-eh.resume: ; preds = %catch.dispatch
- %exn = load i8*, i8** %exn.slot
- %sel4 = load i32, i32* %ehselector.slot
- %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn, 0
- %lpad.val5 = insertvalue { i8*, i32 } %lpad.val, i32 %sel4, 1
- resume { i8*, i32 } %lpad.val5
}
; CHECK-LABEL: use_both:
diff --git a/test/CodeGen/X86/seh-exception-code.ll b/test/CodeGen/X86/seh-exception-code.ll
index e481a8e308c..20e1544e0b5 100644
--- a/test/CodeGen/X86/seh-exception-code.ll
+++ b/test/CodeGen/X86/seh-exception-code.ll
@@ -14,11 +14,11 @@ entry:
to label %__try.cont unwind label %catch.dispatch
catch.dispatch: ; preds = %entry
- %pad = catchpad [i8* null]
- to label %__except unwind label %catchendblock
+ %cs = catchswitch within none [label %__except] unwind to caller
__except: ; preds = %catch.dispatch
- catchret %pad to label %__except.1
+ %pad = catchpad within %cs [i8* null]
+ catchret from %pad to label %__except.1
__except.1: ; preds = %__except
%code = call i32 @llvm.eh.exceptioncode(token %pad)
@@ -27,15 +27,12 @@ __except.1: ; preds = %__except
__try.cont: ; preds = %entry, %__except.1
ret void
-
-catchendblock: ; preds = %catch.dispatch
- catchendpad unwind to caller
}
; CHECK-LABEL: ehcode:
; CHECK: xorl %ecx, %ecx
; CHECK: callq f
-; CHECK: # %catch.dispatch
+; CHECK: # %__except
; CHECK: movl %eax, %ecx
; CHECK-NEXT: callq f
diff --git a/test/CodeGen/X86/seh-finally.ll b/test/CodeGen/X86/seh-finally.ll
index 57c2c8c20f7..67bce81a66a 100644
--- a/test/CodeGen/X86/seh-finally.ll
+++ b/test/CodeGen/X86/seh-finally.ll
@@ -17,15 +17,9 @@ invoke.cont: ; preds = %entry
ret i32 0
lpad: ; preds = %entry
- %p = cleanuppad []
- %call2 = invoke i32 @puts(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @str_recovered, i64 0, i64 0))
- to label %invoke.cont1 unwind label %endpad
-
-invoke.cont1: ; preds = %lpad
- cleanupret %p unwind to caller
-
-endpad: ; preds = %lpad
- cleanupendpad %p unwind to caller
+ %p = cleanuppad within none []
+ %call2 = call i32 @puts(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @str_recovered, i64 0, i64 0))
+ cleanupret from %p unwind to caller
}
; X64-LABEL: main:
diff --git a/test/CodeGen/X86/seh-safe-div-win32.ll b/test/CodeGen/X86/seh-safe-div-win32.ll
index 7f83b0c6466..3f88696fe60 100644
--- a/test/CodeGen/X86/seh-safe-div-win32.ll
+++ b/test/CodeGen/X86/seh-safe-div-win32.ll
@@ -31,28 +31,22 @@ entry:
to label %__try.cont unwind label %lpad0
lpad0:
- %p0 = catchpad [i8* bitcast (i32 ()* @safe_div_filt0 to i8*)]
- to label %handler0 unwind label %endpad0
+ %cs0 = catchswitch within none [label %handler0] unwind label %lpad1
handler0:
+ %p0 = catchpad within %cs0 [i8* bitcast (i32 ()* @safe_div_filt0 to i8*)]
call void @puts(i8* getelementptr ([27 x i8], [27 x i8]* @str1, i32 0, i32 0))
store i32 -1, i32* %r, align 4
- catchret %p0 to label %__try.cont
-
-endpad0:
- catchendpad unwind label %lpad1
+ catchret from %p0 to label %__try.cont
lpad1:
- %p1 = catchpad [i8* bitcast (i32 ()* @safe_div_filt1 to i8*)]
- to label %handler1 unwind label %endpad1
+ %cs1 = catchswitch within none [label %handler1] unwind to caller
handler1:
+ %p1 = catchpad within %cs1 [i8* bitcast (i32 ()* @safe_div_filt1 to i8*)]
call void @puts(i8* getelementptr ([29 x i8], [29 x i8]* @str2, i32 0, i32 0))
store i32 -2, i32* %r, align 4
- catchret %p1 to label %__try.cont
-
-endpad1:
- catchendpad unwind to caller
+ catchret from %p1 to label %__try.cont
__try.cont:
%safe_ret = load i32, i32* %r, align 4
@@ -71,13 +65,13 @@ __try.cont:
; Landing pad code
-; CHECK: [[lpad0:LBB0_[0-9]+]]: # %lpad0
+; CHECK: [[handler0:LBB0_[0-9]+]]: # %handler0
; Restore SP
; CHECK: movl {{.*}}(%ebp), %esp
; CHECK: calll _puts
; CHECK: jmp [[cont_bb]]
-; CHECK: [[lpad1:LBB0_[0-9]+]]: # %lpad1
+; CHECK: [[handler1:LBB0_[0-9]+]]: # %handler1
; Restore SP
; CHECK: movl {{.*}}(%ebp), %esp
; CHECK: calll _puts
@@ -87,10 +81,10 @@ __try.cont:
; CHECK: L__ehtable$safe_div:
; CHECK-NEXT: .long -1
; CHECK-NEXT: .long _safe_div_filt1
-; CHECK-NEXT: .long [[lpad1]]
+; CHECK-NEXT: .long [[handler1]]
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long _safe_div_filt0
-; CHECK-NEXT: .long [[lpad0]]
+; CHECK-NEXT: .long [[handler0]]
define void @try_body(i32* %r, i32* %n, i32* %d) {
entry:
diff --git a/test/CodeGen/X86/seh-safe-div.ll b/test/CodeGen/X86/seh-safe-div.ll
index 1c7318b5614..3eeeab09ffb 100644
--- a/test/CodeGen/X86/seh-safe-div.ll
+++ b/test/CodeGen/X86/seh-safe-div.ll
@@ -30,28 +30,22 @@ entry:
to label %__try.cont unwind label %lpad0
lpad0:
- %p0 = catchpad [i8* bitcast (i32 (i8*, i8*)* @safe_div_filt0 to i8*)]
- to label %handler0 unwind label %endpad0
+ %cs0 = catchswitch within none [label %handler0] unwind label %lpad1
handler0:
+ %p0 = catchpad within %cs0 [i8* bitcast (i32 (i8*, i8*)* @safe_div_filt0 to i8*)]
call void @puts(i8* getelementptr ([27 x i8], [27 x i8]* @str1, i32 0, i32 0))
store i32 -1, i32* %r, align 4
- catchret %p0 to label %__try.cont
-
-endpad0:
- catchendpad unwind label %lpad1
+ catchret from %p0 to label %__try.cont
lpad1:
- %p1 = catchpad [i8* bitcast (i32 (i8*, i8*)* @safe_div_filt1 to i8*)]
- to label %handler1 unwind label %endpad1
+ %cs1 = catchswitch within none [label %handler1] unwind to caller
handler1:
+ %p1 = catchpad within %cs1 [i8* bitcast (i32 (i8*, i8*)* @safe_div_filt1 to i8*)]
call void @puts(i8* getelementptr ([29 x i8], [29 x i8]* @str2, i32 0, i32 0))
store i32 -2, i32* %r, align 4
- catchret %p1 to label %__try.cont
-
-endpad1:
- catchendpad unwind to caller
+ catchret from %p1 to label %__try.cont
__try.cont:
%safe_ret = load i32, i32* %r, align 4
@@ -73,12 +67,12 @@ __try.cont:
; Landing pad code
-; CHECK: [[lpad0:\.LBB0_[0-9]+]]: # %lpad0
+; CHECK: [[handler0:\.LBB0_[0-9]+]]: # %handler0
; CHECK: callq puts
; CHECK: movl $-1, [[rloc]]
; CHECK: jmp [[cont_bb]]
-; CHECK: [[lpad1:\.LBB0_[0-9]+]]: # %lpad1
+; CHECK: [[handler1:\.LBB0_[0-9]+]]: # %handler1
; CHECK: callq puts
; CHECK: movl $-2, [[rloc]]
; CHECK: jmp [[cont_bb]]
@@ -89,11 +83,11 @@ __try.cont:
; CHECK-NEXT: .long .Ltmp0@IMGREL+1
; CHECK-NEXT: .long .Ltmp1@IMGREL+1
; CHECK-NEXT: .long safe_div_filt0@IMGREL
-; CHECK-NEXT: .long [[lpad0]]@IMGREL
+; CHECK-NEXT: .long [[handler0]]@IMGREL
; CHECK-NEXT: .long .Ltmp0@IMGREL+1
; CHECK-NEXT: .long .Ltmp1@IMGREL+1
; CHECK-NEXT: .long safe_div_filt1@IMGREL
-; CHECK-NEXT: .long [[lpad1]]@IMGREL
+; CHECK-NEXT: .long [[handler1]]@IMGREL
; CHECK-NEXT: .Llsda_end0:
; CHECK: .text
; CHECK: .seh_endproc
diff --git a/test/CodeGen/X86/seh-stack-realign.ll b/test/CodeGen/X86/seh-stack-realign.ll
index 8494cadddb7..880533b4392 100644
--- a/test/CodeGen/X86/seh-stack-realign.ll
+++ b/test/CodeGen/X86/seh-stack-realign.ll
@@ -23,16 +23,13 @@ entry:
to label %__try.cont unwind label %lpad
lpad: ; preds = %entry
- %p = catchpad [i8* bitcast (i32 ()* @"filt$main" to i8*)]
- to label %__except unwind label %endpad
+ %cs1 = catchswitch within none [label %__except] unwind to caller
__except: ; preds = %lpad
+ %p = catchpad within %cs1 [i8* bitcast (i32 ()* @"filt$main" to i8*)]
%code = load i32, i32* %__exceptioncode, align 4
%call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @str, i32 0, i32 0), i32 %code) #4
- catchret %p to label %__try.cont
-
-endpad:
- catchendpad unwind to caller
+ catchret from %p to label %__try.cont
__try.cont: ; preds = %entry, %__except
ret i32 0
@@ -63,7 +60,7 @@ entry:
; CHECK: movl $0, 40(%esi)
; CHECK: calll _crash
; CHECK: retl
-; CHECK: LBB0_[[lpbb:[0-9]+]]: # %lpad
+; CHECK: LBB0_[[lpbb:[0-9]+]]: # %__except
; Restore ESP
; CHECK: movl -24(%ebp), %esp
; Restore ESI
diff --git a/test/CodeGen/X86/tail-dup-catchret.ll b/test/CodeGen/X86/tail-dup-catchret.ll
index 18682fb690e..3eeb24d20f2 100644
--- a/test/CodeGen/X86/tail-dup-catchret.ll
+++ b/test/CodeGen/X86/tail-dup-catchret.ll
@@ -8,19 +8,16 @@ entry:
to label %try.cont unwind label %catch.dispatch
catch.dispatch: ; preds = %entry
- %0 = catchpad [i8* null, i32 64, i8* null]
- to label %catch unwind label %catchendblock
+ %cs1 = catchswitch within none [label %catch] unwind to caller
catch: ; preds = %catch.dispatch
- catchret %0 to label %try.cont
+ %0 = catchpad within %cs1 [i8* null, i32 64, i8* null]
+ catchret from %0 to label %try.cont
try.cont: ; preds = %entry, %catch
%b.0 = phi i1 [ false, %catch ], [ true, %entry ]
tail call void @h(i1 zeroext %b.0)
ret void
-
-catchendblock: ; preds = %catch.dispatch
- catchendpad unwind to caller
}
; CHECK-LABEL: _f:
diff --git a/test/CodeGen/X86/tail-merge-wineh.ll b/test/CodeGen/X86/tail-merge-wineh.ll
index d0f6b72df24..69c2fda6949 100644
--- a/test/CodeGen/X86/tail-merge-wineh.ll
+++ b/test/CodeGen/X86/tail-merge-wineh.ll
@@ -54,11 +54,11 @@ entry:
to label %unreachable unwind label %catch.dispatch
catch.dispatch: ; preds = %entry
- %1 = catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
- to label %catch unwind label %catchendblock
+ %cs1 = catchswitch within none [label %catch] unwind label %catch.dispatch.7
catch: ; preds = %catch.dispatch
- catchret %1 to label %catchret.dest
+ %1 = catchpad within %cs1 [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
+ catchret from %1 to label %catchret.dest
catchret.dest: ; preds = %catch
br label %try.cont
@@ -70,11 +70,11 @@ try.cont: ; preds = %catchret.dest
to label %unreachable unwind label %catch.dispatch.2
catch.dispatch.2: ; preds = %try.cont
- %3 = catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
- to label %catch.4 unwind label %catchendblock.3
+ %cs2 = catchswitch within none [label %catch.4] unwind label %catch.dispatch.7
catch.4: ; preds = %catch.dispatch.2
- catchret %3 to label %catchret.dest.5
+ %3 = catchpad within %cs2 [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
+ catchret from %3 to label %catchret.dest.5
catchret.dest.5: ; preds = %catch.4
br label %try.cont.6
@@ -82,15 +82,12 @@ catchret.dest.5: ; preds = %catch.4
try.cont.6: ; preds = %catchret.dest.5
br label %try.cont.11
-catchendblock.3: ; preds = %catch.dispatch.2
- catchendpad unwind label %catch.dispatch.7
-
-catch.dispatch.7: ; preds = %catchendblock.3, %catchendblock
- %4 = catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
- to label %catch.9 unwind label %catchendblock.8
+catch.dispatch.7:
+ %cs3 = catchswitch within none [label %catch.9] unwind to caller
catch.9: ; preds = %catch.dispatch.7
- catchret %4 to label %catchret.dest.10
+ %4 = catchpad within %cs3 [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
+ catchret from %4 to label %catchret.dest.10
catchret.dest.10: ; preds = %catch.9
br label %try.cont.11
@@ -98,12 +95,6 @@ catchret.dest.10: ; preds = %catch.9
try.cont.11: ; preds = %catchret.dest.10, %try.cont.6
ret void
-catchendblock.8: ; preds = %catch.dispatch.7
- catchendpad unwind to caller
-
-catchendblock: ; preds = %catch.dispatch
- catchendpad unwind label %catch.dispatch.7
-
unreachable: ; preds = %try.cont, %entry
unreachable
}
diff --git a/test/CodeGen/X86/win-catchpad-csrs.ll b/test/CodeGen/X86/win-catchpad-csrs.ll
index b6b4a9319b0..9f7a49536ca 100644
--- a/test/CodeGen/X86/win-catchpad-csrs.ll
+++ b/test/CodeGen/X86/win-catchpad-csrs.ll
@@ -16,7 +16,7 @@ declare void @useints(...)
declare void @f(i32 %p)
declare i32 @__CxxFrameHandler3(...)
-define i32 @try_catch_catch() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+define i32 @try_catch_catch() personality i32 (...)* @__CxxFrameHandler3 {
entry:
%a = call i32 @getint()
%b = call i32 @getint()
@@ -26,22 +26,16 @@ entry:
invoke void @f(i32 1)
to label %try.cont unwind label %catch.dispatch
-catch.dispatch: ; preds = %entry
- %0 = catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
- to label %catch unwind label %catchendblock
-
-catch:
- invoke void @f(i32 2)
- to label %invoke.cont.2 unwind label %catchendblock
-
-invoke.cont.2: ; preds = %catch
- catchret %0 to label %try.cont
-
-try.cont: ; preds = %entry, %invoke.cont.2, %invoke.cont.3
+try.cont:
ret i32 0
-catchendblock: ; preds = %catch,
- catchendpad unwind to caller
+catch.dispatch:
+ %cs = catchswitch within none [label %handler1] unwind to caller
+
+handler1:
+ %h1 = catchpad within %cs [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
+ call void @f(i32 2)
+ catchret from %h1 to label %try.cont
}
; X86-LABEL: _try_catch_catch:
@@ -71,7 +65,7 @@ catchendblock: ; preds = %catch,
; X86: jmp [[contbb]]
; X86: "?catch$[[catch1bb:[0-9]+]]@?0?try_catch_catch@4HA":
-; X86: LBB0_[[catch1bb]]: # %catch.dispatch{{$}}
+; X86: LBB0_[[catch1bb]]: # %handler1{{$}}
; X86: pushl %ebp
; X86-NOT: pushl
; X86: subl $16, %esp
@@ -120,7 +114,7 @@ catchendblock: ; preds = %catch,
; X64: retq
; X64: "?catch$[[catch1bb:[0-9]+]]@?0?try_catch_catch@4HA":
-; X64: LBB0_[[catch1bb]]: # %catch.dispatch{{$}}
+; X64: LBB0_[[catch1bb]]: # %handler1{{$}}
; X64: movq %rdx, 16(%rsp)
; X64: pushq %rbp
; X64: .seh_pushreg 5
@@ -159,18 +153,15 @@ entry:
invoke void @f(i32 1)
to label %try.cont unwind label %catch.dispatch
-catch.dispatch: ; preds = %entry
- %0 = catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
- to label %catch unwind label %catchendblock
+catch.dispatch:
+ %cs = catchswitch within none [label %handler1] unwind to caller
-catch:
- catchret %0 to label %try.cont
+handler1:
+ %0 = catchpad within %cs [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
+ catchret from %0 to label %try.cont
-try.cont: ; preds = %entry, %invoke.cont.2, %invoke.cont.3
+try.cont:
ret i32 0
-
-catchendblock: ; preds = %catch,
- catchendpad unwind to caller
}
; X64-LABEL: try_one_csr:
@@ -198,7 +189,7 @@ catchendblock: ; preds = %catch,
; X64: retq
; X64: "?catch$[[catch1bb:[0-9]+]]@?0?try_one_csr@4HA":
-; X64: LBB1_[[catch1bb]]: # %catch.dispatch{{$}}
+; X64: LBB1_[[catch1bb]]: # %handler1{{$}}
; X64: movq %rdx, 16(%rsp)
; X64: pushq %rbp
; X64: .seh_pushreg 5
@@ -226,18 +217,15 @@ entry:
invoke void @f(i32 1)
to label %try.cont unwind label %catch.dispatch
-catch.dispatch: ; preds = %entry
- %0 = catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
- to label %catch unwind label %catchendblock
+catch.dispatch:
+ %cs = catchswitch within none [label %handler1] unwind to caller
-catch:
- catchret %0 to label %try.cont
+handler1:
+ %cp1 = catchpad within %cs [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
+ catchret from %cp1 to label %try.cont
-try.cont: ; preds = %entry, %invoke.cont.2, %invoke.cont.3
+try.cont:
ret i32 0
-
-catchendblock: ; preds = %catch,
- catchendpad unwind to caller
}
; X64-LABEL: try_no_csr:
@@ -259,7 +247,7 @@ catchendblock: ; preds = %catch,
; X64: retq
; X64: "?catch$[[catch1bb:[0-9]+]]@?0?try_no_csr@4HA":
-; X64: LBB2_[[catch1bb]]: # %catch.dispatch{{$}}
+; X64: LBB2_[[catch1bb]]: # %handler1{{$}}
; X64: movq %rdx, 16(%rsp)
; X64: pushq %rbp
; X64: .seh_pushreg 5
diff --git a/test/CodeGen/X86/win-catchpad-nested-cxx.ll b/test/CodeGen/X86/win-catchpad-nested-cxx.ll
new file mode 100644
index 00000000000..22ce7e5cd87
--- /dev/null
+++ b/test/CodeGen/X86/win-catchpad-nested-cxx.ll
@@ -0,0 +1,105 @@
+; RUN: llc -verify-machineinstrs -mtriple=i686-pc-windows-msvc < %s \
+; RUN: | FileCheck --check-prefix=CHECK --check-prefix=X86 %s
+; RUN: llc -verify-machineinstrs -mtriple=x86_64-pc-windows-msvc < %s \
+; RUN: | FileCheck --check-prefix=CHECK --check-prefix=X64 %s
+
+; Loosely based on IR for this C++ source code:
+; void f(int p);
+; void try_in_catch() {
+; try {
+; f(1);
+; } catch (...) {
+; try {
+; f(2);
+; } catch (...) {
+; f(3);
+; }
+; }
+; }
+
+declare void @f(i32 %p)
+declare i32 @__CxxFrameHandler3(...)
+
+define i32 @try_in_catch() personality i32 (...)* @__CxxFrameHandler3 {
+entry:
+ invoke void @f(i32 1)
+ to label %try.cont unwind label %catch.dispatch.1
+try.cont:
+ ret i32 0
+
+catch.dispatch.1:
+ %cs1 = catchswitch within none [label %handler1] unwind to caller
+handler1:
+ %h1 = catchpad within %cs1 [i8* null, i32 64, i8* null]
+ invoke void @f(i32 2)
+ to label %catchret1 unwind label %catch.dispatch.2
+catchret1:
+ catchret from %h1 to label %try.cont
+
+catch.dispatch.2:
+ %cs2 = catchswitch within %h1 [label %handler2] unwind to caller
+handler2:
+ %h2 = catchpad within %cs2 [i8* null, i32 64, i8* null]
+ call void @f(i32 3)
+ catchret from %h2 to label %catchret1
+}
+
+; X86-LABEL: L__ehtable$try_in_catch:
+; X64-LABEL: $cppxdata$try_in_catch:
+; CHECK-NEXT: .long 429065506
+; CHECK-NEXT: .long 4
+; CHECK-NEXT: .long ($stateUnwindMap$try_in_catch)
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long ($tryMap$try_in_catch)
+; ip2state num + ptr
+; X86-NEXT: .long 0
+; X86-NEXT: .long 0
+; X64-NEXT: .long 7
+; X64-NEXT: .long ($ip2state$try_in_catch)
+; unwindhelp offset
+; X64-NEXT: .long 40
+; CHECK-NEXT: .long 0
+; EHFlags
+; CHECK-NEXT: .long 1
+
+; CHECK: $tryMap$try_in_catch:
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 2
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long ($handlerMap$0$try_in_catch)
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 3
+; CHECK-NEXT: .long 1
+; CHECK-NEXT: .long ($handlerMap$1$try_in_catch)
+
+; CHECK: $handlerMap$0$try_in_catch:
+; CHECK-NEXT: .long 64
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long "?catch${{[0-9]+}}@?0?try_in_catch@4HA"
+; X64-NEXT: .long 56
+
+; CHECK: $handlerMap$1$try_in_catch:
+; CHECK-NEXT: .long 64
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long 0
+; CHECK-NEXT: .long "?catch${{[0-9]+}}@?0?try_in_catch@4HA"
+; X64-NEXT: .long 56
+
+; X64: $ip2state$try_in_catch:
+; X64-NEXT: .long .Lfunc_begin0@IMGREL
+; X64-NEXT: .long -1
+; X64-NEXT: .long .Ltmp0@IMGREL+1
+; X64-NEXT: .long 0
+; X64-NEXT: .long .Ltmp1@IMGREL+1
+; X64-NEXT: .long -1
+; X64-NEXT: .long "?catch$2@?0?try_in_catch@4HA"@IMGREL
+; X64-NEXT: .long 1
+; X64-NEXT: .long .Ltmp2@IMGREL+1
+; X64-NEXT: .long 2
+; X64-NEXT: .long .Ltmp3@IMGREL+1
+; X64-NEXT: .long 1
+; X64-NEXT: .long "?catch$4@?0?try_in_catch@4HA"@IMGREL
+; X64-NEXT: .long 3
diff --git a/test/CodeGen/X86/win-catchpad-nested.ll b/test/CodeGen/X86/win-catchpad-nested.ll
index 25adfdf8c80..d20f9f69a5e 100644
--- a/test/CodeGen/X86/win-catchpad-nested.ll
+++ b/test/CodeGen/X86/win-catchpad-nested.ll
@@ -7,26 +7,25 @@ declare void @f()
define void @test1() personality void ()* @ProcessCLRException {
entry:
invoke void @f()
- to label %exit unwind label %outer.pad
-outer.pad:
- %outer = catchpad [i32 1]
- to label %outer.catch unwind label %outer.end
+ to label %exit unwind label %catch.dispatch.1
+exit:
+ ret void
+
+catch.dispatch.1:
+ %cs1 = catchswitch within none [label %outer.catch] unwind to caller
+
outer.catch:
+ %cp1 = catchpad within %cs1 [i32 1]
invoke void @f()
- to label %outer.ret unwind label %inner.pad
-inner.pad:
- %inner = catchpad [i32 2]
- to label %inner.ret unwind label %inner.end
-inner.ret:
- catchret %inner to label %outer.ret
-inner.end:
- catchendpad unwind label %outer.end
+ to label %outer.ret unwind label %catch.dispatch.2
outer.ret:
- catchret %outer to label %exit
-outer.end:
- catchendpad unwind to caller
-exit:
- ret void
+ catchret from %cp1 to label %exit
+
+catch.dispatch.2:
+ %cs2 = catchswitch within %cp1 [label %inner.catch] unwind to caller
+inner.catch:
+ %cp2 = catchpad within %cs2 [i32 2]
+ catchret from %cp2 to label %outer.ret
}
; Check the catchret targets
@@ -37,7 +36,7 @@ exit:
; CHECK-NEXT: # %outer.ret
; CHECK-NEXT: leaq [[Exit]](%rip), %rax
; CHECK: retq # CATCHRET
-; CHECK: {{^[^: ]+}}: # %inner.pad
+; CHECK: {{^[^: ]+}}: # %inner.catch
; CHECK: .seh_endprolog
; CHECK-NEXT: leaq [[OuterRet]](%rip), %rax
; CHECK: retq # CATCHRET
diff --git a/test/CodeGen/X86/win-catchpad-varargs.ll b/test/CodeGen/X86/win-catchpad-varargs.ll
index a2988a3059e..6508f3bd7d6 100644
--- a/test/CodeGen/X86/win-catchpad-varargs.ll
+++ b/test/CodeGen/X86/win-catchpad-varargs.ll
@@ -13,20 +13,17 @@ entry:
to label %return unwind label %catch.dispatch
catch.dispatch: ; preds = %entry
- %0 = catchpad [i8* null, i32 64, i8* null]
- to label %catch unwind label %catchendblock
+ %cs1 = catchswitch within none [label %catch] unwind to caller
catch: ; preds = %catch.dispatch
+ %0 = catchpad within %cs1 [i8* null, i32 64, i8* null]
%ap1 = bitcast i8** %ap to i8*
call void @llvm.va_start(i8* %ap1)
%argp.cur = load i8*, i8** %ap
%1 = bitcast i8* %argp.cur to i32*
%arg2 = load i32, i32* %1
call void @llvm.va_end(i8* %ap1)
- catchret %0 to label %return
-
-catchendblock: ; preds = %catch.dispatch
- catchendpad unwind to caller
+ catchret from %0 to label %return
return: ; preds = %entry, %catch
%retval.0 = phi i32 [ %arg2, %catch ], [ -1, %entry ]
diff --git a/test/CodeGen/X86/win-catchpad.ll b/test/CodeGen/X86/win-catchpad.ll
index d9c8307cb08..5bd25046130 100644
--- a/test/CodeGen/X86/win-catchpad.ll
+++ b/test/CodeGen/X86/win-catchpad.ll
@@ -28,7 +28,7 @@ declare void @f(i32 %p, i32* %l)
declare i1 @getbool()
declare i32 @__CxxFrameHandler3(...)
-define i32 @try_catch_catch() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+define i32 @try_catch_catch() personality i32 (...)* @__CxxFrameHandler3 {
entry:
%e.addr = alloca i32
%local = alloca i32
@@ -36,33 +36,21 @@ entry:
to label %try.cont unwind label %catch.dispatch
catch.dispatch: ; preds = %entry
- %0 = catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i32* %e.addr]
- to label %catch unwind label %catch.dispatch.2
+ %cs = catchswitch within none [label %handler1, label %handler2] unwind to caller
-catch: ; preds = %catch.dispatch
+handler1:
+ %h1 = catchpad within %cs [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i32* %e.addr]
%e = load i32, i32* %e.addr
- invoke void @f(i32 %e, i32* %local)
- to label %invoke.cont.2 unwind label %catchendblock
+ call void @f(i32 %e, i32* %local)
+ catchret from %h1 to label %try.cont
-invoke.cont.2: ; preds = %catch
- catchret %0 to label %try.cont
+handler2:
+ %h2 = catchpad within %cs [i8* null, i32 64, i8* null]
+ call void @f(i32 3, i32* %local)
+ catchret from %h2 to label %try.cont
-catch.dispatch.2: ; preds = %catch.dispatch
- %1 = catchpad [i8* null, i32 u0x40, i8* null]
- to label %catch.2 unwind label %catchendblock
-
-catch.2: ; preds = %catch.dispatch.2
- invoke void @f(i32 3, i32* %local)
- to label %invoke.cont.3 unwind label %catchendblock
-
-invoke.cont.3: ; preds = %catch.2
- catchret %1 to label %try.cont
-
-try.cont: ; preds = %entry, %invoke.cont.2, %invoke.cont.3
+try.cont:
ret i32 0
-
-catchendblock: ; preds = %catch, %catch.2, %catch.dispatch.2
- catchendpad unwind to caller
}
; X86-LABEL: _try_catch_catch:
@@ -76,25 +64,25 @@ catchendblock: ; preds = %catch, %catch.2, %c
; X86: retl
; X86: [[restorebb1:LBB0_[0-9]+]]: # Block address taken
-; X86-NEXT: # %invoke.cont.2
+; X86-NEXT: # %handler1
; X86-NEXT: addl $12, %ebp
; X86: jmp [[contbb]]
; FIXME: These should be de-duplicated.
; X86: [[restorebb2:LBB0_[0-9]+]]: # Block address taken
-; X86-NEXT: # %invoke.cont.3
+; X86-NEXT: # %handler2
; X86-NEXT: addl $12, %ebp
; X86: jmp [[contbb]]
; X86: "?catch$[[catch1bb:[0-9]+]]@?0?try_catch_catch@4HA":
-; X86: LBB0_[[catch1bb]]: # %catch.dispatch{{$}}
+; X86: LBB0_[[catch1bb]]: # %handler1{{$}}
; X86: pushl %ebp
; X86: subl $8, %esp
; X86: addl $12, %ebp
; X86: movl %esp, -[[sp_offset]](%ebp)
-; X86: leal -[[local_offs]](%ebp), %[[addr_reg:[a-z]+]]
-; X86: movl -32(%ebp), %[[e_reg:[a-z]+]]
-; X86: movl $1, -{{[0-9]+}}(%ebp)
+; X86-DAG: movl -32(%ebp), %[[e_reg:[a-z]+]]
+; X86-DAG: leal -[[local_offs]](%ebp), %[[addr_reg:[a-z]+]]
+; X86-DAG: movl $1, -{{[0-9]+}}(%ebp)
; X86-DAG: movl %[[addr_reg]], 4(%esp)
; X86-DAG: movl %[[e_reg]], (%esp)
; X86: calll _f
@@ -104,13 +92,13 @@ catchendblock: ; preds = %catch, %catch.2, %c
; X86-NEXT: retl
; X86: "?catch$[[catch2bb:[0-9]+]]@?0?try_catch_catch@4HA":
-; X86: LBB0_[[catch2bb]]: # %catch.dispatch.2{{$}}
+; X86: LBB0_[[catch2bb]]: # %handler2{{$}}
; X86: pushl %ebp
; X86: subl $8, %esp
; X86: addl $12, %ebp
; X86: movl %esp, -[[sp_offset]](%ebp)
-; X86: leal -[[local_offs]](%ebp), %[[addr_reg:[a-z]+]]
-; X86: movl $1, -{{[0-9]+}}(%ebp)
+; X86-DAG: leal -[[local_offs]](%ebp), %[[addr_reg:[a-z]+]]
+; X86-DAG: movl $1, -{{[0-9]+}}(%ebp)
; X86-DAG: movl %[[addr_reg]], 4(%esp)
; X86-DAG: movl $3, (%esp)
; X86: calll _f
@@ -151,7 +139,7 @@ catchendblock: ; preds = %catch, %catch.2, %c
; X64: retq
; X64: "?catch$[[catch1bb:[0-9]+]]@?0?try_catch_catch@4HA":
-; X64: LBB0_[[catch1bb]]: # %catch.dispatch{{$}}
+; X64: LBB0_[[catch1bb]]: # %handler1{{$}}
; X64: movq %rdx, 16(%rsp)
; X64: pushq %rbp
; X64: .seh_pushreg 5
@@ -159,7 +147,6 @@ catchendblock: ; preds = %catch, %catch.2, %c
; X64: .seh_stackalloc 32
; X64: leaq 48(%rdx), %rbp
; X64: .seh_endprologue
-; X64-DAG: .Ltmp4
; X64-DAG: leaq -[[local_offs]](%rbp), %rdx
; X64-DAG: movl -12(%rbp), %ecx
; X64: callq f
@@ -169,7 +156,7 @@ catchendblock: ; preds = %catch, %catch.2, %c
; X64-NEXT: retq
; X64: "?catch$[[catch2bb:[0-9]+]]@?0?try_catch_catch@4HA":
-; X64: LBB0_[[catch2bb]]: # %catch.dispatch.2{{$}}
+; X64: LBB0_[[catch2bb]]: # %handler2{{$}}
; X64: movq %rdx, 16(%rsp)
; X64: pushq %rbp
; X64: .seh_pushreg 5
@@ -180,7 +167,6 @@ catchendblock: ; preds = %catch, %catch.2, %c
; X64-DAG: leaq -[[local_offs]](%rbp), %rdx
; X64-DAG: movl $3, %ecx
; X64: callq f
-; X64: .Ltmp3
; X64: leaq [[contbb]](%rip), %rax
; X64-NEXT: addq $32, %rsp
; X64-NEXT: popq %rbp
@@ -192,7 +178,7 @@ catchendblock: ; preds = %catch, %catch.2, %c
; X64-NEXT: .long ($stateUnwindMap$try_catch_catch)@IMGREL
; X64-NEXT: .long 1
; X64-NEXT: .long ($tryMap$try_catch_catch)@IMGREL
-; X64-NEXT: .long 4
+; X64-NEXT: .long 5
; X64-NEXT: .long ($ip2state$try_catch_catch)@IMGREL
; X64-NEXT: .long 40
; X64-NEXT: .long 0
@@ -222,33 +208,35 @@ catchendblock: ; preds = %catch, %catch.2, %c
; X64-NEXT: .long -1
; X64-NEXT: .long .Ltmp0@IMGREL+1
; X64-NEXT: .long 0
-; X64-NEXT: .long .Ltmp4@IMGREL+1
-; X64-NEXT: .long 1
-; X64-NEXT: .long .Ltmp3@IMGREL+1
+; X64-NEXT: .long .Ltmp1@IMGREL+1
; X64-NEXT: .long -1
+; X64-NEXT: .long "?catch$[[catch1bb]]@?0?try_catch_catch@4HA"@IMGREL
+; X64-NEXT: .long 1
+; X64-NEXT: .long "?catch$[[catch2bb]]@?0?try_catch_catch@4HA"@IMGREL
+; X64-NEXT: .long 1
-define i32 @branch_to_normal_dest() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+define i32 @branch_to_normal_dest() personality i32 (...)* @__CxxFrameHandler3 {
entry:
invoke void @f(i32 1, i32* null)
to label %try.cont unwind label %catch.dispatch
catch.dispatch:
- %0 = catchpad [i8* null, i32 64, i8* null]
- to label %catch unwind label %catchendblock
+ %cs1 = catchswitch within none [label %catch] unwind to caller
catch:
+ %cp1 = catchpad within %cs1 [i8* null, i32 64, i8* null]
+ br label %loop
+
+loop:
%V = call i1 @getbool()
- br i1 %V, label %catch, label %catch.done
+ br i1 %V, label %loop, label %catch.done
catch.done:
- catchret %0 to label %try.cont
+ catchret from %cp1 to label %try.cont
try.cont:
ret i32 0
-
-catchendblock:
- catchendpad unwind to caller
}
; X86-LABEL: _branch_to_normal_dest:
@@ -262,17 +250,16 @@ catchendblock:
; X86-NEXT: addl $12, %ebp
; X86: jmp [[contbb]]
-; X86: "?catch$[[catchdispbb:[0-9]+]]@?0?branch_to_normal_dest@4HA":
-; X86: LBB1_[[catchdispbb]]: # %catch.dispatch{{$}}
+; X86: "?catch$[[catchbb:[0-9]+]]@?0?branch_to_normal_dest@4HA":
+; X86: LBB1_[[catchbb]]: # %catch{{$}}
; X86: pushl %ebp
; X86: subl $8, %esp
; X86: addl $12, %ebp
-
-; X86: LBB1_[[catchbb:[0-9]+]]: # %catch
-; X86: movl $-1, -16(%ebp)
+; X86: LBB1_[[loopbb:[0-9]+]]: # %loop
+; X86: movl $1, -16(%ebp)
; X86: calll _getbool
; X86: testb $1, %al
-; X86: jne LBB1_[[catchbb]]
+; X86: jne LBB1_[[loopbb]]
; X86: # %catch.done
; X86-NEXT: movl $[[restorebb]], %eax
; X86-NEXT: addl $8, %esp
@@ -284,7 +271,7 @@ catchendblock:
; X86-NEXT: .long 64
; X86-NEXT: .long 0
; X86-NEXT: .long 0
-; X86-NEXT: .long "?catch$[[catchdispbb]]@?0?branch_to_normal_dest@4HA"
+; X86-NEXT: .long "?catch$[[catchbb]]@?0?branch_to_normal_dest@4HA"
; X64-LABEL: branch_to_normal_dest:
; X64: # %entry
@@ -305,7 +292,7 @@ catchendblock:
; X64: retq
; X64: "?catch$[[catchbb:[0-9]+]]@?0?branch_to_normal_dest@4HA":
-; X64: LBB1_[[catchbb]]: # %catch.dispatch{{$}}
+; X64: LBB1_[[catchbb]]: # %catch{{$}}
; X64: movq %rdx, 16(%rsp)
; X64: pushq %rbp
; X64: .seh_pushreg 5
@@ -313,7 +300,7 @@ catchendblock:
; X64: .seh_stackalloc 32
; X64: leaq 48(%rdx), %rbp
; X64: .seh_endprologue
-; X64: .LBB1_[[normal_dest_bb:[0-9]+]]: # %catch
+; X64: .LBB1_[[normal_dest_bb:[0-9]+]]: # %loop
; X64: callq getbool
; X64: testb $1, %al
; X64: jne .LBB1_[[normal_dest_bb]]
@@ -329,7 +316,7 @@ catchendblock:
; X64-NEXT: .long ($stateUnwindMap$branch_to_normal_dest)@IMGREL
; X64-NEXT: .long 1
; X64-NEXT: .long ($tryMap$branch_to_normal_dest)@IMGREL
-; X64-NEXT: .long 3
+; X64-NEXT: .long 4
; X64-NEXT: .long ($ip2state$branch_to_normal_dest)@IMGREL
; X64-NEXT: .long 40
; X64-NEXT: .long 0
@@ -362,3 +349,5 @@ catchendblock:
; X64-NEXT: .long 0
; X64-NEXT: .long .Ltmp[[after_call]]@IMGREL+1
; X64-NEXT: .long -1
+; X64-NEXT: .long "?catch$[[catchbb]]@?0?branch_to_normal_dest@4HA"@IMGREL
+; X64-NEXT: .long 1
diff --git a/test/CodeGen/X86/win-cleanuppad.ll b/test/CodeGen/X86/win-cleanuppad.ll
index 27bb6e2abed..37090c2f6bc 100644
--- a/test/CodeGen/X86/win-cleanuppad.ll
+++ b/test/CodeGen/X86/win-cleanuppad.ll
@@ -14,9 +14,9 @@ invoke.cont: ; preds = %entry
ret void
ehcleanup: ; preds = %entry
- %0 = cleanuppad []
+ %0 = cleanuppad within none []
call x86_thiscallcc void @"\01??1Dtor@@QAE@XZ"(%struct.Dtor* %o) #2
- cleanupret %0 unwind to caller
+ cleanupret from %0 unwind to caller
}
; CHECK: simple_cleanup: # @simple_cleanup
@@ -77,14 +77,14 @@ invoke.cont.2: ; preds = %invoke.cont.1
ret void
cleanup.inner: ; preds = %invoke.cont
- %0 = cleanuppad []
+ %0 = cleanuppad within none []
call x86_thiscallcc void @"\01??1Dtor@@QAE@XZ"(%struct.Dtor* %o2) #2
- cleanupret %0 unwind label %cleanup.outer
+ cleanupret from %0 unwind label %cleanup.outer
cleanup.outer: ; preds = %invoke.cont.1, %cleanup.inner, %entry
- %1 = cleanuppad []
+ %1 = cleanuppad within none []
call x86_thiscallcc void @"\01??1Dtor@@QAE@XZ"(%struct.Dtor* %o1) #2
- cleanupret %1 unwind to caller
+ cleanupret from %1 unwind to caller
}
; X86-LABEL: _nested_cleanup:
diff --git a/test/CodeGen/X86/win-funclet-cfi.ll b/test/CodeGen/X86/win-funclet-cfi.ll
index 52589ee1918..95afa75a709 100644
--- a/test/CodeGen/X86/win-funclet-cfi.ll
+++ b/test/CodeGen/X86/win-funclet-cfi.ll
@@ -9,24 +9,21 @@ entry:
to label %unreachable unwind label %cleanupblock
cleanupblock:
- %cleanp = cleanuppad []
+ %cleanp = cleanuppad within none []
call void @g()
- cleanupret %cleanp unwind label %catch.dispatch
+ cleanupret from %cleanp unwind label %catch.dispatch
catch.dispatch:
- %cp = catchpad [i8* null, i32 64, i8* null]
- to label %catch unwind label %catchendblock
+ %cs1 = catchswitch within none [label %catch] unwind to caller
catch:
+ %cp = catchpad within %cs1 [i8* null, i32 64, i8* null]
call void @g()
- catchret %cp to label %try.cont
+ catchret from %cp to label %try.cont
try.cont:
ret void
-catchendblock:
- catchendpad unwind to caller
-
unreachable:
unreachable
}
@@ -70,7 +67,7 @@ declare i32 @__CxxFrameHandler3(...)
; CHECK: "?catch$[[catch:[0-9]+]]@?0??f@@YAXXZ@4HA":
; CHECK: .seh_proc "?catch$[[catch]]@?0??f@@YAXXZ@4HA"
; CHECK-NEXT: .seh_handler __CxxFrameHandler3, @unwind, @except
-; CHECK: LBB0_[[catch]]: # %catch.dispatch{{$}}
+; CHECK: LBB0_[[catch]]: # %catch{{$}}
; Emit CFI for pushing RBP.
; CHECK: movq %rdx, 16(%rsp)
diff --git a/test/CodeGen/X86/win-mixed-ehpersonality.ll b/test/CodeGen/X86/win-mixed-ehpersonality.ll
index 9b6916554e5..f7b6d0702eb 100644
--- a/test/CodeGen/X86/win-mixed-ehpersonality.ll
+++ b/test/CodeGen/X86/win-mixed-ehpersonality.ll
@@ -18,12 +18,10 @@ cont:
ret i32 0
lpad:
- %p = catchpad [i8* bitcast (i32 (i8*, i8*)* @filt_g to i8*)]
- to label %catch unwind label %endpad
+ %cs = catchswitch within none [label %catch] unwind to caller
catch:
- catchret %p to label %ret1
-endpad:
- catchendpad unwind to caller
+ %p = catchpad within %cs [i8* bitcast (i32 (i8*, i8*)* @filt_g to i8*)]
+ catchret from %p to label %ret1
ret1:
ret i32 1
@@ -39,7 +37,7 @@ define internal i32 @filt_g(i8*, i8*) {
; CHECK: xorl %eax, %eax
; CHECK: .LBB0_[[epilogue:[0-9]+]]
; CHECK: retq
-; CHECK: # %lpad
+; CHECK: # %catch{{$}}
; CHECK: movl $1, %eax
; CHECK: jmp .LBB0_[[epilogue]]
diff --git a/test/CodeGen/X86/win32-eh-states.ll b/test/CodeGen/X86/win32-eh-states.ll
index cb7b053e14d..fe3639b97a4 100644
--- a/test/CodeGen/X86/win32-eh-states.ll
+++ b/test/CodeGen/X86/win32-eh-states.ll
@@ -1,4 +1,5 @@
-; RUN: llc -mtriple=i686-pc-windows-msvc < %s | FileCheck %s
+; RUN: llc -mtriple=i686-pc-windows-msvc < %s | FileCheck %s --check-prefix=X86
+; RUN: llc -mtriple=x86_64-pc-windows-msvc < %s | FileCheck %s --check-prefix=X64
; Based on this source:
; extern "C" void may_throw(int);
@@ -40,59 +41,167 @@ invoke.cont: ; preds = %entry
to label %try.cont.9 unwind label %lpad
try.cont.9: ; preds = %invoke.cont.3, %invoke.cont, %catch.7
- ; FIXME: Something about our CFG breaks TailDuplication. This empy asm blocks
- ; it so we can focus on testing the state numbering.
- call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"()
ret void
lpad: ; preds = %catch, %entry
- %p1 = catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
- to label %catch unwind label %end.inner.catch
+ %cs1 = catchswitch within none [label %catch] unwind label %lpad.1
catch: ; preds = %lpad.1
+ %p1 = catchpad within %cs1 [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
invoke void @may_throw(i32 3)
- to label %invoke.cont.3 unwind label %end.inner.catch
+ to label %invoke.cont.3 unwind label %lpad.1
invoke.cont.3: ; preds = %catch
- catchret %p1 to label %try.cont.9
-
-
-end.inner.catch:
- catchendpad unwind label %lpad.1
+ catchret from %p1 to label %try.cont.9
lpad.1: ; preds = %invoke.cont
- %p2 = catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
- to label %catch.7 unwind label %eh.resume
+ %cs2 = catchswitch within none [label %catch.7] unwind to caller
catch.7:
- invoke void @may_throw(i32 4)
- to label %invoke.cont.10 unwind label %eh.resume
+ %p2 = catchpad within %cs2 [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
+ call void @may_throw(i32 4)
+ catchret from %p2 to label %try.cont.9
+}
+
+; X86-LABEL: _f:
+; X86: movl $-1, [[state:[-0-9]+]](%ebp)
+; X86: movl $___ehhandler$f, {{.*}}
+;
+; X86: movl $0, [[state]](%ebp)
+; X86: movl $1, (%esp)
+; X86: calll _may_throw
+;
+; X86: movl $1, [[state]](%ebp)
+; X86: movl $2, (%esp)
+; X86: calll _may_throw
+;
+; X86: movl $2, [[state]](%ebp)
+; X86: movl $3, (%esp)
+; X86: calll _may_throw
+;
+; X86: movl $3, [[state]](%ebp)
+; X86: movl $4, (%esp)
+; X86: calll _may_throw
+
+
+; X64-LABEL: f:
+; X64-LABEL: $ip2state$f:
+; X64-NEXT: .long .Lfunc_begin0@IMGREL
+; X64-NEXT: .long -1
+; X64-NEXT: .long .Ltmp{{.*}}@IMGREL+1
+; X64-NEXT: .long 0
+; X64-NEXT: .long .Ltmp{{.*}}@IMGREL+1
+; X64-NEXT: .long 1
+; X64-NEXT: .long .Ltmp{{.*}}@IMGREL+1
+; X64-NEXT: .long -1
+; X64-NEXT: .long "?catch${{.*}}@?0?f@4HA"@IMGREL
+; X64-NEXT: .long 2
+; X64-NEXT: .long "?catch${{.*}}@?0?f@4HA"@IMGREL
+; X64-NEXT: .long 3
+
+; Based on this source:
+; extern "C" void may_throw(int);
+; struct S { ~S(); };
+; void g() {
+; S x;
+; try {
+; may_throw(-1);
+; } catch (...) {
+; may_throw(0);
+; {
+; S y;
+; may_throw(1);
+; }
+; may_throw(2);
+; }
+; }
-invoke.cont.10:
- catchret %p2 to label %try.cont.9
+%struct.S = type { i8 }
+declare void @"\01??1S@@QEAA@XZ"(%struct.S*)
-eh.resume: ; preds = %catch.dispatch.4
- catchendpad unwind to caller
+define void @g() personality i32 (...)* @__CxxFrameHandler3 {
+entry:
+ %x = alloca %struct.S, align 1
+ %y = alloca %struct.S, align 1
+ invoke void @may_throw(i32 -1)
+ to label %unreachable unwind label %catch.dispatch
+
+catch.dispatch: ; preds = %entry
+ %0 = catchswitch within none [label %catch] unwind label %ehcleanup5
+
+catch: ; preds = %catch.dispatch
+ %1 = catchpad within %0 [i8* null, i32 64, i8* null]
+ invoke void @may_throw(i32 0)
+ to label %invoke.cont unwind label %ehcleanup5
+
+invoke.cont: ; preds = %catch
+ invoke void @may_throw(i32 1)
+ to label %invoke.cont2 unwind label %ehcleanup
+
+invoke.cont2: ; preds = %invoke.cont
+ invoke void @"\01??1S@@QEAA@XZ"(%struct.S* nonnull %y)
+ to label %invoke.cont3 unwind label %ehcleanup5
+
+invoke.cont3: ; preds = %invoke.cont2
+ invoke void @may_throw(i32 2)
+ to label %invoke.cont4 unwind label %ehcleanup5
+
+invoke.cont4: ; preds = %invoke.cont3
+ catchret from %1 to label %try.cont
+
+try.cont: ; preds = %invoke.cont4
+ call void @"\01??1S@@QEAA@XZ"(%struct.S* nonnull %x)
+ ret void
+
+ehcleanup: ; preds = %invoke.cont
+ %2 = cleanuppad within %1 []
+ call void @"\01??1S@@QEAA@XZ"(%struct.S* nonnull %y)
+ cleanupret from %2 unwind label %ehcleanup5
+
+ehcleanup5: ; preds = %invoke.cont2, %invoke.cont3, %ehcleanup, %catch, %catch.dispatch
+ %3 = cleanuppad within none []
+ call void @"\01??1S@@QEAA@XZ"(%struct.S* nonnull %x)
+ cleanupret from %3 unwind to caller
+
+unreachable: ; preds = %entry
+ unreachable
}
-; CHECK-LABEL: _f:
-; CHECK: movl $-1, [[state:[-0-9]+]](%ebp)
-; CHECK: movl $___ehhandler$f, {{.*}}
+; X86-LABEL: _g:
+; X86: movl $-1, [[state:[-0-9]+]](%ebp)
+; X86: movl $___ehhandler$g, {{.*}}
;
-; CHECK: movl $0, [[state]](%ebp)
-; CHECK: movl $1, (%esp)
-; CHECK: calll _may_throw
+; X86: movl $1, [[state]](%ebp)
+; X86: movl $-1, (%esp)
+; X86: calll _may_throw
;
-; CHECK: movl $1, [[state]](%ebp)
-; CHECK: movl $2, (%esp)
-; CHECK: calll _may_throw
+; X86: movl $2, [[state]](%ebp)
+; X86: movl $0, (%esp)
+; X86: calll _may_throw
;
-; CHECK: movl $2, [[state]](%ebp)
-; CHECK: movl $3, (%esp)
-; CHECK: calll _may_throw
+; X86: movl $3, [[state]](%ebp)
+; X86: movl $1, (%esp)
+; X86: calll _may_throw
;
-; CHECK: movl $3, [[state]](%ebp)
-; CHECK: movl $4, (%esp)
-; CHECK: calll _may_throw
-
-; CHECK: .safeseh ___ehhandler$f
+; X86: movl $2, [[state]](%ebp)
+; X86: movl $2, (%esp)
+; X86: calll _may_throw
+
+; X64-LABEL: g:
+; X64-LABEL: $ip2state$g:
+; X64-NEXT: .long .Lfunc_begin1@IMGREL
+; X64-NEXT: .long -1
+; X64-NEXT: .long .Ltmp{{.*}}@IMGREL+1
+; X64-NEXT: .long 1
+; X64-NEXT: .long .Ltmp{{.*}}@IMGREL+1
+; X64-NEXT: .long -1
+; X64-NEXT: .long "?catch${{.*}}@?0?g@4HA"@IMGREL
+; X64-NEXT: .long 2
+; X64-NEXT: .long .Ltmp{{.*}}@IMGREL+1
+; X64-NEXT: .long 3
+; X64-NEXT: .long .Ltmp{{.*}}@IMGREL+1
+; X64-NEXT: .long 2
+
+
+; X86: .safeseh ___ehhandler$f
+; X86: .safeseh ___ehhandler$g
diff --git a/test/CodeGen/X86/win32-eh.ll b/test/CodeGen/X86/win32-eh.ll
index 87926a463f7..73c7b486a55 100644
--- a/test/CodeGen/X86/win32-eh.ll
+++ b/test/CodeGen/X86/win32-eh.ll
@@ -19,12 +19,10 @@ entry:
cont:
ret void
lpad:
- %p = catchpad [i8* bitcast (i32 ()* @catchall_filt to i8*)]
- to label %catch unwind label %endpad
+ %cs = catchswitch within none [label %catch] unwind to caller
catch:
- catchret %p to label %cont
-endpad:
- catchendpad unwind to caller
+ %p = catchpad within %cs [i8* bitcast (i32 ()* @catchall_filt to i8*)]
+ catchret from %p to label %cont
}
; CHECK-LABEL: _use_except_handler3:
@@ -45,7 +43,7 @@ endpad:
; CHECK: movl -28(%ebp), %[[next:[^ ,]*]]
; CHECK: movl %[[next]], %fs:0
; CHECK: retl
-; CHECK: LBB1_2: # %lpad{{$}}
+; CHECK: LBB1_2: # %catch{{$}}
; CHECK: .section .xdata,"dr"
; CHECK-LABEL: L__ehtable$use_except_handler3:
@@ -60,12 +58,10 @@ entry:
cont:
ret void
lpad:
- %p = catchpad [i8* bitcast (i32 ()* @catchall_filt to i8*)]
- to label %catch unwind label %endpad
+ %cs = catchswitch within none [label %catch] unwind to caller
catch:
- catchret %p to label %cont
-endpad:
- catchendpad unwind to caller
+ %p = catchpad within %cs [i8* bitcast (i32 ()* @catchall_filt to i8*)]
+ catchret from %p to label %cont
}
; CHECK-LABEL: _use_except_handler4:
@@ -86,7 +82,7 @@ endpad:
; CHECK: movl -28(%ebp), %[[next:[^ ,]*]]
; CHECK: movl %[[next]], %fs:0
; CHECK: retl
-; CHECK: LBB2_2: # %lpad{{$}}
+; CHECK: LBB2_2: # %catch{{$}}
; CHECK: .section .xdata,"dr"
; CHECK-LABEL: L__ehtable$use_except_handler4:
@@ -105,14 +101,10 @@ cont:
ret void
catchall:
- %p = catchpad [i8* null, i32 64, i8* null]
- to label %catch unwind label %endcatch
-
+ %cs = catchswitch within none [label %catch] unwind to caller
catch:
- catchret %p to label %cont
-
-endcatch:
- catchendpad unwind to caller
+ %p = catchpad within %cs [i8* null, i32 64, i8* null]
+ catchret from %p to label %cont
}
; CHECK-LABEL: _use_CxxFrameHandler3:
diff --git a/test/CodeGen/X86/win32-seh-catchpad-realign.ll b/test/CodeGen/X86/win32-seh-catchpad-realign.ll
index 24db1649eb8..23aeea37c11 100644
--- a/test/CodeGen/X86/win32-seh-catchpad-realign.ll
+++ b/test/CodeGen/X86/win32-seh-catchpad-realign.ll
@@ -15,17 +15,14 @@ entry:
to label %__try.cont unwind label %catch.dispatch
catch.dispatch: ; preds = %entry
- %pad = catchpad [i8* bitcast (i32 ()* @"\01?filt$0@0@realigned_try@@" to i8*)]
- to label %__except.ret unwind label %catchendblock
+ %cs1 = catchswitch within none [label %__except.ret] unwind to caller
__except.ret: ; preds = %catch.dispatch
- catchret %pad to label %__try.cont
+ %pad = catchpad within %cs1 [i8* bitcast (i32 ()* @"\01?filt$0@0@realigned_try@@" to i8*)]
+ catchret from %pad to label %__try.cont
__try.cont: ; preds = %entry, %__except.ret
ret void
-
-catchendblock: ; preds = %catch.dispatch
- catchendpad unwind to caller
}
; Function Attrs: nounwind argmemonly
@@ -69,7 +66,7 @@ declare i32 @_except_handler3(...)
; CHECK: popl %ebp
; CHECK: retl
;
-; CHECK: LBB0_1: # %catch.dispatch
+; CHECK: LBB0_1: # %__except.ret
; Restore ESP
; CHECK: movl -24(%ebp), %esp
; Recompute ESI by subtracting 60 from the end of the registration node.
diff --git a/test/CodeGen/X86/win32-seh-catchpad.ll b/test/CodeGen/X86/win32-seh-catchpad.ll
index 4e373af23e4..88dea367572 100644
--- a/test/CodeGen/X86/win32-seh-catchpad.ll
+++ b/test/CodeGen/X86/win32-seh-catchpad.ll
@@ -11,10 +11,11 @@ entry:
to label %invoke.cont unwind label %catch.dispatch
catch.dispatch: ; preds = %entry
- %0 = catchpad [i8* bitcast (i32 ()* @try_except_filter_catchall to i8*)] to label %__except.ret unwind label %catchendblock
+ %cs1 = catchswitch within none [label %__except.ret] unwind to caller
__except.ret: ; preds = %catch.dispatch
- catchret %0 to label %__except
+ %0 = catchpad within %cs1 [i8* bitcast (i32 ()* @try_except_filter_catchall to i8*)]
+ catchret from %0 to label %__except
__except: ; preds = %__except.ret
call void @f(i32 2)
@@ -24,9 +25,6 @@ __try.cont: ; preds = %__except, %invoke.c
call void @f(i32 3)
ret void
-catchendblock: ; preds = %catch.dispatch
- catchendpad unwind to caller
-
invoke.cont: ; preds = %entry
br label %__try.cont
}
@@ -77,81 +75,69 @@ entry:
to label %__try.cont unwind label %catch.dispatch
catch.dispatch: ; preds = %entry
- %0 = catchpad [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)] to label %__except.ret unwind label %catchendblock
+ %cs1 = catchswitch within none [label %__except.ret] unwind label %catch.dispatch.11
__except.ret: ; preds = %catch.dispatch
- catchret %0 to label %__try.cont
+ %0 = catchpad within %cs1 [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)]
+ catchret from %0 to label %__try.cont
__try.cont: ; preds = %entry, %__except.ret
invoke void @crash() #3
to label %__try.cont.9 unwind label %catch.dispatch.5
catch.dispatch.5: ; preds = %__try.cont
- %1 = catchpad [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)] to label %__except.ret.7 unwind label %catchendblock.6
+ %cs2 = catchswitch within none [label %__except.ret.7] unwind label %catch.dispatch.11
__except.ret.7: ; preds = %catch.dispatch.5
- catchret %1 to label %__try.cont.9
+ %1 = catchpad within %cs2 [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)]
+ catchret from %1 to label %__try.cont.9
__try.cont.9: ; preds = %__try.cont, %__except.ret.7
invoke void @crash() #3
to label %__try.cont.15 unwind label %catch.dispatch.11
catch.dispatch.11: ; preds = %catchendblock, %catchendblock.6, %__try.cont.9
- %2 = catchpad [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)] to label %__except.ret.13 unwind label %catchendblock.12
+ %cs3 = catchswitch within none [label %__except.ret.13] unwind label %catch.dispatch.17
__except.ret.13: ; preds = %catch.dispatch.11
- catchret %2 to label %__try.cont.15
+ %2 = catchpad within %cs3 [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)]
+ catchret from %2 to label %__try.cont.15
__try.cont.15: ; preds = %__try.cont.9, %__except.ret.13
invoke void @crash() #3
to label %__try.cont.35 unwind label %catch.dispatch.17
catch.dispatch.17: ; preds = %catchendblock.12, %__try.cont.15
- %3 = catchpad [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)] to label %__except.ret.19 unwind label %catchendblock.18
+ %cs4 = catchswitch within none [label %__except.ret.19] unwind to caller
__except.ret.19: ; preds = %catch.dispatch.17
- catchret %3 to label %__except.20
+ %3 = catchpad within %cs4 [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)]
+ catchret from %3 to label %__except.20
__except.20: ; preds = %__except.ret.19
invoke void @crash() #3
to label %__try.cont.27 unwind label %catch.dispatch.23
catch.dispatch.23: ; preds = %__except.20
- %4 = catchpad [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)] to label %__except.ret.25 unwind label %catchendblock.24
+ %cs5 = catchswitch within none [label %__except.ret.25] unwind to caller
__except.ret.25: ; preds = %catch.dispatch.23
- catchret %4 to label %__try.cont.27
+ %4 = catchpad within %cs5 [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)]
+ catchret from %4 to label %__try.cont.27
__try.cont.27: ; preds = %__except.20, %__except.ret.25
invoke void @crash() #3
to label %__try.cont.35 unwind label %catch.dispatch.30
catch.dispatch.30: ; preds = %__try.cont.27
- %5 = catchpad [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)] to label %__except.ret.32 unwind label %catchendblock.31
+ %cs6 = catchswitch within none [label %__except.ret.32] unwind to caller
__except.ret.32: ; preds = %catch.dispatch.30
- catchret %5 to label %__try.cont.35
+ %5 = catchpad within %cs6 [i8* bitcast (i32 ()* @nested_exceptions_filter_catchall to i8*)]
+ catchret from %5 to label %__try.cont.35
__try.cont.35: ; preds = %__try.cont.15, %__try.cont.27, %__except.ret.32
ret void
-
-catchendblock.31: ; preds = %catch.dispatch.30
- catchendpad unwind to caller
-
-catchendblock.24: ; preds = %catch.dispatch.23
- catchendpad unwind to caller
-
-catchendblock.18: ; preds = %catch.dispatch.17
- catchendpad unwind to caller
-
-catchendblock.12: ; preds = %catch.dispatch.11
- catchendpad unwind label %catch.dispatch.17
-
-catchendblock.6: ; preds = %catch.dispatch.5
- catchendpad unwind label %catch.dispatch.11
-
-catchendblock: ; preds = %catch.dispatch
- catchendpad unwind label %catch.dispatch.11
}
; This table is equivalent to the one produced by MSVC, even if it isn't in
@@ -162,19 +148,19 @@ catchendblock: ; preds = %catch.dispatch
; CHECK: .long -1
; CHECK: .long _nested_exceptions_filter_catchall
; CHECK: .long LBB
-; CHECK: .long -1
+; CHECK: .long 0
; CHECK: .long _nested_exceptions_filter_catchall
; CHECK: .long LBB
-; CHECK: .long -1
+; CHECK: .long 1
; CHECK: .long _nested_exceptions_filter_catchall
; CHECK: .long LBB
-; CHECK: .long 2
+; CHECK: .long 1
; CHECK: .long _nested_exceptions_filter_catchall
; CHECK: .long LBB
-; CHECK: .long 3
+; CHECK: .long -1
; CHECK: .long _nested_exceptions_filter_catchall
; CHECK: .long LBB
-; CHECK: .long 3
+; CHECK: .long -1
; CHECK: .long _nested_exceptions_filter_catchall
; CHECK: .long LBB
@@ -203,21 +189,19 @@ entry:
to label %__except unwind label %catch.dispatch
catch.dispatch: ; preds = %entry
- %0 = catchpad [i8* bitcast (i32 ()* @try_except_filter_catchall to i8*)] to label %__except.ret unwind label %catchendblock
+ %cs1 = catchswitch within none [label %__except.ret] unwind to caller
__except.ret: ; preds = %catch.dispatch
+ %0 = catchpad within %cs1 [i8* bitcast (i32 ()* @try_except_filter_catchall to i8*)]
call void @f(i32 2)
- catchret %0 to label %__except
+ catchret from %0 to label %__except
__except:
ret void
-
-catchendblock: ; preds = %catch.dispatch
- catchendpad unwind to caller
}
; CHECK-LABEL: _code_in_catchpad:
-; CHECK: # %catch.dispatch
+; CHECK: # %__except.ret
; CHECK-NEXT: movl -24(%ebp), %esp
; CHECK-NEXT: addl $12, %ebp
; CHECK-NEXT: movl $-1, -16(%ebp)
diff --git a/test/CodeGen/X86/win32-seh-cleanupendpad.ll b/test/CodeGen/X86/win32-seh-nested-finally.ll
index 35d9bfeb66e..c91a14278ec 100644
--- a/test/CodeGen/X86/win32-seh-cleanupendpad.ll
+++ b/test/CodeGen/X86/win32-seh-nested-finally.ll
@@ -17,26 +17,17 @@ invoke.cont.1: ; preds = %invoke.cont
ret void
ehcleanup: ; preds = %entry
- %0 = cleanuppad []
+ %0 = cleanuppad within none []
invoke void @f(i32 2) #3
- to label %invoke.cont.2 unwind label %ehcleanup.end
+ to label %invoke.cont.2 unwind label %ehcleanup.3
invoke.cont.2: ; preds = %ehcleanup
- cleanupret %0 unwind label %ehcleanup.3
-
-ehcleanup.end: ; preds = %ehcleanup
- cleanupendpad %0 unwind label %ehcleanup.3
+ cleanupret from %0 unwind label %ehcleanup.3
ehcleanup.3: ; preds = %invoke.cont.2, %ehcleanup.end, %invoke.cont
- %1 = cleanuppad []
- invoke void @f(i32 3) #3
- to label %invoke.cont.4 unwind label %ehcleanup.end.5
-
-invoke.cont.4: ; preds = %ehcleanup.3
- cleanupret %1 unwind to caller
-
-ehcleanup.end.5: ; preds = %ehcleanup.3
- cleanupendpad %1 unwind to caller
+ %1 = cleanuppad within none []
+ call void @f(i32 3) #3
+ cleanupret from %1 unwind to caller
}
declare void @f(i32) #0
diff --git a/test/CodeGen/WinEH/wineh-coreclr.ll b/test/CodeGen/X86/wineh-coreclr.ll
index 079993f74db..7bbc64ece8e 100644
--- a/test/CodeGen/WinEH/wineh-coreclr.ll
+++ b/test/CodeGen/X86/wineh-coreclr.ll
@@ -13,7 +13,7 @@ declare i8 addrspace(1)* @llvm.eh.exceptionpointer.p1i8(token)
; f(2);
; } catch (type1) {
; f(3);
-; } catch (type2) [
+; } catch (type2) {
; f(4);
; try {
; f(5);
@@ -50,10 +50,10 @@ inner_try:
invoke void @f(i32 2)
to label %finally.clone unwind label %catch1.pad
catch1.pad:
-; CHECK: .seh_proc [[L_catch1:[^ ]+]]
- %catch1 = catchpad [i32 1]
- to label %catch1.body unwind label %catch2.pad
+ %cs1 = catchswitch within none [label %catch1.body, label %catch2.body] unwind label %finally.pad
catch1.body:
+ %catch1 = catchpad within %cs1 [i32 1]
+; CHECK: .seh_proc [[L_catch1:[^ ]+]]
; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]
; ^ all funclets use the same frame size
; CHECK: movq [[PSPSymOffset]](%rcx), %rcx
@@ -71,14 +71,12 @@ catch1.body:
; CHECK-NEXT: callq f
; CHECK-NEXT: [[L_after_f3:.+]]:
invoke void @f(i32 3)
- to label %catch1.ret unwind label %catch.end
+ to label %catch1.ret unwind label %finally.pad
catch1.ret:
- catchret %catch1 to label %finally.clone
-catch2.pad:
-; CHECK: .seh_proc [[L_catch2:[^ ]+]]
- %catch2 = catchpad [i32 2]
- to label %catch2.body unwind label %catch.end
+ catchret from %catch1 to label %finally.clone
catch2.body:
+ %catch2 = catchpad within %cs1 [i32 2]
+; CHECK: .seh_proc [[L_catch2:[^ ]+]]
; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]
; ^ all funclets use the same frame size
; CHECK: movq [[PSPSymOffset]](%rcx), %rcx
@@ -96,7 +94,7 @@ catch2.body:
; CHECK-NEXT: callq f
; CHECK-NEXT: [[L_after_f4:.+]]:
invoke void @f(i32 4)
- to label %try_in_catch unwind label %catch.end
+ to label %try_in_catch unwind label %finally.pad
try_in_catch:
; CHECK: # %try_in_catch
; CHECK: [[L_before_f5:.+]]:
@@ -107,7 +105,7 @@ try_in_catch:
to label %catch2.ret unwind label %fault.pad
fault.pad:
; CHECK: .seh_proc [[L_fault:[^ ]+]]
- %fault = cleanuppad [i32 undef]
+ %fault = cleanuppad within none [i32 undef]
; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]
; ^ all funclets use the same frame size
; CHECK: movq [[PSPSymOffset]](%rcx), %rcx
@@ -120,21 +118,17 @@ fault.pad:
; CHECK-NEXT: callq f
; CHECK-NEXT: [[L_after_f6:.+]]:
invoke void @f(i32 6)
- to label %fault.ret unwind label %fault.end
+ to label %fault.ret unwind label %finally.pad
fault.ret:
- cleanupret %fault unwind label %catch.end
-fault.end:
- cleanupendpad %fault unwind label %catch.end
+ cleanupret from %fault unwind label %finally.pad
catch2.ret:
- catchret %catch2 to label %finally.clone
-catch.end:
- catchendpad unwind label %finally.pad
+ catchret from %catch2 to label %finally.clone
finally.clone:
call void @f(i32 7)
br label %tail
finally.pad:
; CHECK: .seh_proc [[L_finally:[^ ]+]]
- %finally = cleanuppad []
+ %finally = cleanuppad within none []
; CHECK: .seh_stackalloc [[FuncletFrameSize:[0-9]+]]
; ^ all funclets use the same frame size
; CHECK: movq [[PSPSymOffset]](%rcx), %rcx
@@ -142,136 +136,132 @@ finally.pad:
; CHECK: movq %rcx, [[PSPSymOffset]](%rsp)
; CHECK: leaq [[FPOffset]](%rcx), %rbp
; CHECK: .seh_endprologue
-; CHECK: [[L_before_f7:.+]]:
; CHECK-NEXT: movl $7, %ecx
; CHECK-NEXT: callq f
-; CHECK-NEXT: [[L_after_f7:.+]]:
- invoke void @f(i32 7)
- to label %finally.ret unwind label %finally.end
-finally.ret:
- cleanupret %finally unwind to caller
-finally.end:
- cleanupendpad %finally unwind to caller
+ call void @f(i32 7)
+ cleanupret from %finally unwind to caller
tail:
call void @f(i32 8)
ret void
; CHECK: [[L_end:.*func_end.*]]:
}
+; FIXME: Verify that the new clauses are correct and re-enable these checks.
+
; Now check for EH table in xdata (following standard xdata)
-; CHECK-LABEL: .section .xdata
+; CHECKX-LABEL: .section .xdata
; standard xdata comes here
-; CHECK: .long 4{{$}}
+; CHECKX: .long 4{{$}}
; ^ number of funclets
-; CHECK-NEXT: .long [[L_catch1]]-[[L_begin]]
+; CHECKX-NEXT: .long [[L_catch1]]-[[L_begin]]
; ^ offset from L_begin to start of 1st funclet
-; CHECK-NEXT: .long [[L_catch2]]-[[L_begin]]
+; CHECKX-NEXT: .long [[L_catch2]]-[[L_begin]]
; ^ offset from L_begin to start of 2nd funclet
-; CHECK-NEXT: .long [[L_fault]]-[[L_begin]]
+; CHECKX-NEXT: .long [[L_fault]]-[[L_begin]]
; ^ offset from L_begin to start of 3rd funclet
-; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
+; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]]
; ^ offset from L_begin to start of 4th funclet
-; CHECK-NEXT: .long [[L_end]]-[[L_begin]]
+; CHECKX-NEXT: .long [[L_end]]-[[L_begin]]
; ^ offset from L_begin to end of last funclet
-; CHECK-NEXT: .long 7
+; CHECKX-NEXT: .long 7
; ^ number of EH clauses
; Clause 1: call f(2) is guarded by catch1
-; CHECK-NEXT: .long 0
+; CHECKX-NEXT: .long 0
; ^ flags (0 => catch handler)
-; CHECK-NEXT: .long ([[L_before_f2]]-[[L_begin]])+1
+; CHECKX-NEXT: .long ([[L_before_f2]]-[[L_begin]])+1
; ^ offset of start of clause
-; CHECK-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1
+; CHECKX-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1
; ^ offset of end of clause
-; CHECK-NEXT: .long [[L_catch1]]-[[L_begin]]
+; CHECKX-NEXT: .long [[L_catch1]]-[[L_begin]]
; ^ offset of start of handler
-; CHECK-NEXT: .long [[L_catch2]]-[[L_begin]]
+; CHECKX-NEXT: .long [[L_catch2]]-[[L_begin]]
; ^ offset of end of handler
-; CHECK-NEXT: .long 1
+; CHECKX-NEXT: .long 1
; ^ type token of catch (from catchpad)
; Clause 2: call f(2) is also guarded by catch2
-; CHECK-NEXT: .long 0
+; CHECKX-NEXT: .long 0
; ^ flags (0 => catch handler)
-; CHECK-NEXT: .long ([[L_before_f2]]-[[L_begin]])+1
+; CHECKX-NEXT: .long ([[L_before_f2]]-[[L_begin]])+1
; ^ offset of start of clause
-; CHECK-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1
+; CHECKX-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1
; ^ offset of end of clause
-; CHECK-NEXT: .long [[L_catch2]]-[[L_begin]]
+; CHECKX-NEXT: .long [[L_catch2]]-[[L_begin]]
; ^ offset of start of handler
-; CHECK-NEXT: .long [[L_fault]]-[[L_begin]]
+; CHECKX-NEXT: .long [[L_fault]]-[[L_begin]]
; ^ offset of end of handler
-; CHECK-NEXT: .long 2
+; CHECKX-NEXT: .long 2
; ^ type token of catch (from catchpad)
; Clause 3: calls f(1) and f(2) are guarded by finally
-; CHECK-NEXT: .long 2
+; CHECKX-NEXT: .long 2
; ^ flags (2 => finally handler)
-; CHECK-NEXT: .long ([[L_before_f1]]-[[L_begin]])+1
+; CHECKX-NEXT: .long ([[L_before_f1]]-[[L_begin]])+1
; ^ offset of start of clause
-; CHECK-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1
+; CHECKX-NEXT: .long ([[L_after_f2]]-[[L_begin]])+1
; ^ offset of end of clause
-; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
+; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]]
; ^ offset of start of handler
-; CHECK-NEXT: .long [[L_end]]-[[L_begin]]
+; CHECKX-NEXT: .long [[L_end]]-[[L_begin]]
; ^ offset of end of handler
-; CHECK-NEXT: .long 0
+; CHECKX-NEXT: .long 0
; ^ type token slot (null for finally)
; Clause 4: call f(3) is guarded by finally
; This is a "duplicate" because the protected range (f(3))
; is in funclet catch1 but the finally's immediate parent
; is the main function, not that funclet.
-; CHECK-NEXT: .long 10
+; CHECKX-NEXT: .long 10
; ^ flags (2 => finally handler | 8 => duplicate)
-; CHECK-NEXT: .long ([[L_before_f3]]-[[L_begin]])+1
+; CHECKX-NEXT: .long ([[L_before_f3]]-[[L_begin]])+1
; ^ offset of start of clause
-; CHECK-NEXT: .long ([[L_after_f3]]-[[L_begin]])+1
+; CHECKX-NEXT: .long ([[L_after_f3]]-[[L_begin]])+1
; ^ offset of end of clause
-; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
+; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]]
; ^ offset of start of handler
-; CHECK-NEXT: .long [[L_end]]-[[L_begin]]
+; CHECKX-NEXT: .long [[L_end]]-[[L_begin]]
; ^ offset of end of handler
-; CHECK-NEXT: .long 0
+; CHECKX-NEXT: .long 0
; ^ type token slot (null for finally)
; Clause 5: call f(5) is guarded by fault
-; CHECK-NEXT: .long 4
+; CHECKX-NEXT: .long 4
; ^ flags (4 => fault handler)
-; CHECK-NEXT: .long ([[L_before_f5]]-[[L_begin]])+1
+; CHECKX-NEXT: .long ([[L_before_f5]]-[[L_begin]])+1
; ^ offset of start of clause
-; CHECK-NEXT: .long ([[L_after_f5]]-[[L_begin]])+1
+; CHECKX-NEXT: .long ([[L_after_f5]]-[[L_begin]])+1
; ^ offset of end of clause
-; CHECK-NEXT: .long [[L_fault]]-[[L_begin]]
+; CHECKX-NEXT: .long [[L_fault]]-[[L_begin]]
; ^ offset of start of handler
-; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
+; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]]
; ^ offset of end of handler
-; CHECK-NEXT: .long 0
+; CHECKX-NEXT: .long 0
; ^ type token slot (null for fault)
; Clause 6: calls f(4) and f(5) are guarded by finally
; This is a "duplicate" because the protected range (f(4)-f(5))
; is in funclet catch2 but the finally's immediate parent
; is the main function, not that funclet.
-; CHECK-NEXT: .long 10
+; CHECKX-NEXT: .long 10
; ^ flags (2 => finally handler | 8 => duplicate)
-; CHECK-NEXT: .long ([[L_before_f4]]-[[L_begin]])+1
+; CHECKX-NEXT: .long ([[L_before_f4]]-[[L_begin]])+1
; ^ offset of start of clause
-; CHECK-NEXT: .long ([[L_after_f5]]-[[L_begin]])+1
+; CHECKX-NEXT: .long ([[L_after_f5]]-[[L_begin]])+1
; ^ offset of end of clause
-; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
+; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]]
; ^ offset of start of handler
-; CHECK-NEXT: .long [[L_end]]-[[L_begin]]
+; CHECKX-NEXT: .long [[L_end]]-[[L_begin]]
; ^ offset of end of handler
-; CHECK-NEXT: .long 0
+; CHECKX-NEXT: .long 0
; ^ type token slot (null for finally)
; Clause 7: call f(6) is guarded by finally
; This is a "duplicate" because the protected range (f(3))
; is in funclet catch1 but the finally's immediate parent
; is the main function, not that funclet.
-; CHECK-NEXT: .long 10
+; CHECKX-NEXT: .long 10
; ^ flags (2 => finally handler | 8 => duplicate)
-; CHECK-NEXT: .long ([[L_before_f6]]-[[L_begin]])+1
+; CHECKX-NEXT: .long ([[L_before_f6]]-[[L_begin]])+1
; ^ offset of start of clause
-; CHECK-NEXT: .long ([[L_after_f6]]-[[L_begin]])+1
+; CHECKX-NEXT: .long ([[L_after_f6]]-[[L_begin]])+1
; ^ offset of end of clause
-; CHECK-NEXT: .long [[L_finally]]-[[L_begin]]
+; CHECKX-NEXT: .long [[L_finally]]-[[L_begin]]
; ^ offset of start of handler
-; CHECK-NEXT: .long [[L_end]]-[[L_begin]]
+; CHECKX-NEXT: .long [[L_end]]-[[L_begin]]
; ^ offset of end of handler
-; CHECK-NEXT: .long 0
+; CHECKX-NEXT: .long 0
; ^ type token slot (null for finally)
diff --git a/test/CodeGen/WinEH/wineh-exceptionpointer.ll b/test/CodeGen/X86/wineh-exceptionpointer.ll
index 47ffc35acac..9c1f0aaf3de 100644
--- a/test/CodeGen/WinEH/wineh-exceptionpointer.ll
+++ b/test/CodeGen/X86/wineh-exceptionpointer.ll
@@ -11,18 +11,16 @@ entry:
invoke void @f()
to label %exit unwind label %catch.pad
catch.pad:
-; CHECK: {{^[^: ]+}}: # %catch.pad
- %catch = catchpad [i32 5]
- to label %catch.body unwind label %catch.end
+ %cs1 = catchswitch within none [label %catch.body] unwind to caller
catch.body:
- %exn = call i8 addrspace(1)* @llvm.eh.exceptionpointer.p1i8(token %catch)
- %cast_exn = bitcast i8 addrspace(1)* %exn to i32 addrspace(1)*
+ ; CHECK: {{^[^: ]+}}: # %catch.body
; CHECK: movq %rdx, %rcx
; CHECK-NEXT: callq g
+ %catch = catchpad within %cs1 [i32 5]
+ %exn = call i8 addrspace(1)* @llvm.eh.exceptionpointer.p1i8(token %catch)
+ %cast_exn = bitcast i8 addrspace(1)* %exn to i32 addrspace(1)*
call void @g(i32 addrspace(1)* %cast_exn)
- catchret %catch to label %exit
-catch.end:
- catchendpad unwind to caller
+ catchret from %catch to label %exit
exit:
ret void
}
diff --git a/test/Feature/exception.ll b/test/Feature/exception.ll
index c6c436ae83d..05dbfe89645 100644
--- a/test/Feature/exception.ll
+++ b/test/Feature/exception.ll
@@ -31,8 +31,8 @@ entry:
invoke void @_Z3quxv() optsize
to label %exit unwind label %pad
pad:
- %cp = cleanuppad [i7 4]
- cleanupret %cp unwind to caller
+ %cp = cleanuppad within none [i7 4]
+ cleanupret from %cp unwind to caller
exit:
ret void
}
@@ -43,9 +43,9 @@ entry:
invoke void @_Z3quxv() optsize
to label %exit unwind label %pad
cleanup:
- cleanupret %cp unwind label %pad
+ cleanupret from %cp unwind label %pad
pad:
- %cp = cleanuppad []
+ %cp = cleanuppad within none []
br label %cleanup
exit:
ret void
@@ -57,9 +57,9 @@ entry:
invoke void @_Z3quxv() optsize
to label %exit unwind label %pad
cleanup:
- cleanupret %0 unwind label %pad
+ cleanupret from %0 unwind label %pad
pad:
- %0 = cleanuppad []
+ %0 = cleanuppad within none []
br label %cleanup
exit:
ret void
@@ -70,12 +70,10 @@ entry:
invoke void @_Z3quxv() optsize
to label %exit unwind label %pad
pad:
- %cp = catchpad [i7 4]
- to label %catch unwind label %endpad
+ %cs1 = catchswitch within none [label %catch] unwind to caller
catch:
- catchret %cp to label %exit
-endpad:
- catchendpad unwind to caller
+ %cp = catchpad within %cs1 [i7 4]
+ catchret from %cp to label %exit
exit:
ret void
}
@@ -85,13 +83,13 @@ define void @catchret1() personality i32 (...)* @__gxx_personality_v0 {
entry:
invoke void @_Z3quxv() optsize
to label %exit unwind label %pad
-catch:
- catchret %cp to label %exit
+catchret:
+ catchret from %cp to label %exit
pad:
- %cp = catchpad []
- to label %catch unwind label %endpad
-endpad:
- catchendpad unwind to caller
+ %cs1 = catchswitch within none [label %catch] unwind to caller
+catch:
+ %cp = catchpad within %cs1 [i7 4]
+ br label %catchret
exit:
ret void
}
@@ -101,13 +99,13 @@ define void @catchret2() personality i32 (...)* @__gxx_personality_v0 {
entry:
invoke void @_Z3quxv() optsize
to label %exit unwind label %pad
-catch:
- catchret %0 to label %exit
+catchret:
+ catchret from %0 to label %exit
pad:
- %0 = catchpad []
- to label %catch unwind label %endpad
-endpad:
- catchendpad unwind to caller
+ %cs1 = catchswitch within none [label %catch] unwind to caller
+catch:
+ %0 = catchpad within %cs1 [i7 4]
+ br label %catchret
exit:
ret void
}
@@ -117,9 +115,10 @@ entry:
invoke void @_Z3quxv() optsize
to label %exit unwind label %bb2
bb2:
- catchpad [i7 4] to label %exit unwind label %bb3
-bb3:
- catchendpad unwind to caller
+ %cs1 = catchswitch within none [label %catch] unwind to caller
+catch:
+ catchpad within %cs1 [i7 4]
+ br label %exit
exit:
ret i8 0
}
@@ -132,7 +131,7 @@ try.cont:
invoke void @_Z3quxv() optsize
to label %try.cont unwind label %bb
bb:
- terminatepad [i7 4] unwind label %bb
+ terminatepad within none [i7 4] unwind label %bb
}
define void @terminatepad1() personality i32 (...)* @__gxx_personality_v0 {
@@ -143,7 +142,7 @@ try.cont:
invoke void @_Z3quxv() optsize
to label %try.cont unwind label %bb
bb:
- terminatepad [i7 4] unwind to caller
+ terminatepad within none [i7 4] unwind to caller
}
define void @cleanuppad() personality i32 (...)* @__gxx_personality_v0 {
@@ -154,78 +153,6 @@ try.cont:
invoke void @_Z3quxv() optsize
to label %try.cont unwind label %bb
bb:
- cleanuppad [i7 4]
- ret void
-}
-
-define void @catchendpad0() personality i32 (...)* @__gxx_personality_v0 {
-entry:
- br label %try.cont
-
-try.cont:
- invoke void @_Z3quxv() optsize
- to label %try.cont unwind label %bb
-bb:
- catchendpad unwind label %bb
-}
-
-define void @catchendpad1() personality i32 (...)* @__gxx_personality_v0 {
-entry:
- br label %try.cont
-
-try.cont:
- invoke void @_Z3quxv() optsize
- to label %try.cont unwind label %bb
-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:
+ cleanuppad within none [i7 4]
ret void
}
diff --git a/test/Transforms/CodeGenPrepare/catchpad-phi-cast.ll b/test/Transforms/CodeGenPrepare/catchpad-phi-cast.ll
index c0b63b7d6d9..8c5e01e3634 100644
--- a/test/Transforms/CodeGenPrepare/catchpad-phi-cast.ll
+++ b/test/Transforms/CodeGenPrepare/catchpad-phi-cast.ll
@@ -18,9 +18,6 @@ declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #2
; CHECK-LABEL: @test(
define void @test(i32* %addr) personality i32 (...)* @__CxxFrameHandler3 {
-; CHECK: entry:
-; CHECK-NEXT: %x = getelementptr i32, i32* %addr, i32 1
-; CHECK-NEXT: %p1 = bitcast i32* %x to i8*
entry:
%x = getelementptr i32, i32* %addr, i32 1
%p1 = bitcast i32* %x to i8*
@@ -29,7 +26,6 @@ entry:
; CHECK: invoke.cont:
; CHECK-NEXT: %y = getelementptr i32, i32* %addr, i32 2
-; CHECK-NEXT: %p2 = bitcast i32* %y to i8*
invoke.cont:
%y = getelementptr i32, i32* %addr, i32 2
%p2 = bitcast i32* %y to i8*
@@ -40,23 +36,31 @@ done:
ret void
catch1:
- %cp1 = catchpad [] to label %catch.dispatch unwind label %catchend1
+ %cs1 = catchswitch within none [label %handler1] unwind to caller
-catch2:
- %cp2 = catchpad [] to label %catch.dispatch unwind label %catchend2
+handler1:
+ %cp1 = catchpad within %cs1 []
+ br label %catch.shared
+; CHECK: handler1:
+; CHECK-NEXT: catchpad within %cs1
+; CHECK: %[[p1:[0-9]+]] = bitcast i32* %x to i8*
-; CHECK: catch.dispatch:
-; CHECK-NEXT: %p = phi i8* [ %p1, %catch1 ], [ %p2, %catch2 ]
-catch.dispatch:
- %p = phi i8* [ %p1, %catch1 ], [ %p2, %catch2 ]
+catch2:
+ %cs2 = catchswitch within none [label %handler2] unwind to caller
+
+handler2:
+ %cp2 = catchpad within %cs2 []
+ br label %catch.shared
+; CHECK: handler2:
+; CHECK: catchpad within %cs2
+; CHECK: %[[p2:[0-9]+]] = bitcast i32* %y to i8*
+
+; CHECK: catch.shared:
+; CHECK-NEXT: %p = phi i8* [ %[[p1]], %handler1 ], [ %[[p2]], %handler2 ]
+catch.shared:
+ %p = phi i8* [ %p1, %handler1 ], [ %p2, %handler2 ]
call void @g(i8* %p)
unreachable
-
-catchend1:
- catchendpad unwind to caller
-
-catchend2:
- catchendpad unwind to caller
}
; CodeGenPrepare will want to hoist these llvm.dbg.value calls to the phi, but
@@ -75,24 +79,22 @@ ret:
catch.dispatch:
%p = phi i8* [%a, %entry], [%b, %next]
- %cp1 = catchpad [] to label %catch unwind label %catchend
+ %cs1 = catchswitch within none [label %catch] unwind to caller
catch:
+ %cp1 = catchpad within %cs1 []
tail call void @llvm.dbg.value(metadata i8* %p, i64 0, metadata !11, metadata !13), !dbg !14
- invoke void @g(i8* %p) to label %catchret unwind label %catchend
-catchret:
- catchret %cp1 to label %ret
+ call void @g(i8* %p)
+ catchret from %cp1 to label %ret
; CHECK: catch.dispatch:
; CHECK-NEXT: phi i8
-; CHECK-NEXT: catchpad
+; CHECK-NEXT: catchswitch
; CHECK-NOT: llvm.dbg.value
; CHECK: catch:
+; CHECK-NEXT: catchpad
; CHECK-NEXT: call void @llvm.dbg.value
-
-catchend:
- catchendpad unwind to caller
}
!llvm.dbg.cu = !{!0}
diff --git a/test/Transforms/GVN/funclet.ll b/test/Transforms/GVN/funclet.ll
index c9faf8ee4c8..2669256f0bd 100644
--- a/test/Transforms/GVN/funclet.ll
+++ b/test/Transforms/GVN/funclet.ll
@@ -17,12 +17,12 @@ entry:
to label %unreachable unwind label %catch.dispatch
catch.dispatch: ; preds = %entry
- %catchpad = catchpad [i8* null, i32 64, i8* null]
- to label %catch unwind label %catchendblock
+ %cs1 = catchswitch within none [label %catch] unwind to caller
catch: ; preds = %catch.dispatch
+ %catchpad = catchpad within %cs1 [i8* null, i32 64, i8* null]
store i8 5, i8* %b
- catchret %catchpad to label %try.cont
+ catchret from %catchpad to label %try.cont
try.cont: ; preds = %catch
%load_b = load i8, i8* %b
@@ -30,9 +30,6 @@ try.cont: ; preds = %catch
%add = add i8 %load_b, %load_c
ret i8 %add
-catchendblock: ; preds = %catch.dispatch
- catchendpad unwind to caller
-
unreachable: ; preds = %entry
unreachable
}
diff --git a/test/Transforms/GVN/pre-load.ll b/test/Transforms/GVN/pre-load.ll
index c165a5a4932..685df24f62b 100644
--- a/test/Transforms/GVN/pre-load.ll
+++ b/test/Transforms/GVN/pre-load.ll
@@ -399,7 +399,7 @@ define void @test12(i32* %p) personality i32 (...)* @__CxxFrameHandler3 {
; CHECK-LABEL: @test12(
block1:
invoke void @f()
- to label %block2 unwind label %catch
+ to label %block2 unwind label %catch.dispatch
block2:
invoke void @f()
@@ -408,31 +408,25 @@ block2:
block3:
ret void
-catch:
- %c = catchpad []
- to label %catch.dispatch unwind label %catchend
-
catch.dispatch:
- catchret %c to label %block2
+ %cs1 = catchswitch within none [label %catch] unwind label %cleanup2
-; CHECK: catchend:
-; CHECK-NOT: load
-; CHECK-NEXT: catchendpad
-catchend:
- catchendpad unwind label %cleanup2
+catch:
+ %c = catchpad within %cs1 []
+ catchret from %c to label %block2
cleanup:
- %c1 = cleanuppad []
+ %c1 = cleanuppad within none []
store i32 0, i32* %p
- cleanupret %c1 unwind label %cleanup2
+ cleanupret from %c1 unwind label %cleanup2
; CHECK: cleanup2:
; CHECK-NOT: phi
-; CHECK-NEXT: %c2 = cleanuppad []
+; CHECK-NEXT: %c2 = cleanuppad within none []
; CHECK-NEXT: %NOTPRE = load i32, i32* %p
cleanup2:
- %c2 = cleanuppad []
+ %c2 = cleanuppad within none []
%NOTPRE = load i32, i32* %p
call void @g(i32 %NOTPRE)
- cleanupret %c2 unwind to caller
+ cleanupret from %c2 unwind to caller
}
diff --git a/test/Transforms/Inline/PR25155.ll b/test/Transforms/Inline/PR25155.ll
index f2a9ec32fda..aed9a58ab3d 100644
--- a/test/Transforms/Inline/PR25155.ll
+++ b/test/Transforms/Inline/PR25155.ll
@@ -8,21 +8,23 @@ entry:
to label %try.cont unwind label %catch.dispatch
catch.dispatch: ; preds = %entry
- %0 = catchpad [i8* null, i32 64, i8* null]
- to label %catch unwind label %catchendblock
+ %cs1 = catchswitch within none [label %catch] unwind to caller
catch: ; preds = %catch.dispatch
+ %0 = catchpad within %cs1 [i8* null, i32 64, i8* null]
invoke void @dtor()
- to label %invoke.cont.1 unwind label %catchendblock
+ to label %invoke.cont.1 unwind label %ehcleanup
invoke.cont.1: ; preds = %catch
- catchret %0 to label %try.cont
+ catchret from %0 to label %try.cont
try.cont: ; preds = %entry, %invoke.cont.1
ret void
-catchendblock: ; preds = %catch, %catch.dispatch
- catchendpad unwind to caller
+ehcleanup:
+ %cp2 = cleanuppad within none []
+ call void @g()
+ cleanupret from %cp2 unwind to caller
}
; CHECK-LABEL: define void @f(
@@ -31,10 +33,7 @@ catchendblock: ; preds = %catch, %catch.dispa
; CHECK: to label %dtor.exit unwind label %terminate.i
; CHECK: terminate.i:
-; CHECK-NEXT: terminatepad [void ()* @terminate] unwind label %catchendblock
-
-; CHECK: catchendblock:
-; CHECK-NEXT: catchendpad unwind to caller
+; CHECK-NEXT: terminatepad within %0 [void ()* @terminate] unwind label %ehcleanup
declare i32 @__CxxFrameHandler3(...)
@@ -47,7 +46,7 @@ invoke.cont: ; preds = %entry
ret void
terminate: ; preds = %entry
- terminatepad [void ()* @terminate] unwind to caller
+ terminatepad within none [void ()* @terminate] unwind to caller
}
declare void @g()
diff --git a/test/Transforms/InstCombine/token.ll b/test/Transforms/InstCombine/token.ll
index e47109b6164..0929cf7ebee 100644
--- a/test/Transforms/InstCombine/token.ll
+++ b/test/Transforms/InstCombine/token.ll
@@ -9,14 +9,14 @@ bb:
unreachable
unreachable:
- %cl = cleanuppad []
- cleanupret %cl unwind to caller
+ %cl = cleanuppad within none []
+ cleanupret from %cl unwind to caller
}
; CHECK-LABEL: define void @test1(
; CHECK: unreachable:
-; CHECK: %cl = cleanuppad []
-; CHECK: cleanupret %cl unwind to caller
+; CHECK: %cl = cleanuppad within none []
+; CHECK: cleanupret from %cl unwind to caller
define void @test2(i8 %A, i8 %B) personality i32 (...)* @__CxxFrameHandler3 {
bb:
@@ -33,19 +33,15 @@ cont:
catch:
%phi = phi i32 [ %X, %bb ], [ %Y, %cont ]
- %cl = catchpad []
- to label %doit
- unwind label %endpad
+ %cs = catchswitch within none [label %doit] unwind to caller
doit:
+ %cl = catchpad within %cs []
call void @g(i32 %phi)
unreachable
unreachable:
unreachable
-
-endpad:
- catchendpad unwind to caller
}
; CHECK-LABEL: define void @test2(
@@ -73,19 +69,15 @@ cont2:
catch:
%phi = phi i32 [ %X, %bb ], [ %Y, %cont ], [ %Y, %cont2 ]
- %cl = catchpad []
- to label %doit
- unwind label %endpad
+ %cs = catchswitch within none [label %doit] unwind to caller
doit:
+ %cl = catchpad within %cs []
call void @g(i32 %phi)
unreachable
unreachable:
unreachable
-
-endpad:
- catchendpad unwind to caller
}
; CHECK-LABEL: define void @test3(
diff --git a/test/Transforms/LoopStrengthReduce/funclet.ll b/test/Transforms/LoopStrengthReduce/funclet.ll
index 03799ddfdb5..a2da3208a38 100644
--- a/test/Transforms/LoopStrengthReduce/funclet.ll
+++ b/test/Transforms/LoopStrengthReduce/funclet.ll
@@ -20,19 +20,17 @@ throw: ; preds = %throw, %entry
pad: ; preds = %throw
%phi2 = phi i8* [ %tmp96, %throw ]
- terminatepad [] unwind label %blah
+ terminatepad within none [] unwind label %blah
blah:
- catchpad [] to label %unreachable unwind label %blah3
+ %cs = catchswitch within none [label %unreachable] unwind label %blah2
unreachable:
+ catchpad within %cs []
unreachable
-blah3:
- catchendpad unwind label %blah2
-
blah2:
- %cleanuppadi4.i.i.i = cleanuppad []
+ %cleanuppadi4.i.i.i = cleanuppad within none []
br label %loop_body
loop_body: ; preds = %iter, %pad
@@ -45,11 +43,11 @@ iter: ; preds = %loop_body
br i1 undef, label %unwind_out, label %loop_body
unwind_out: ; preds = %iter, %loop_body
- cleanupret %cleanuppadi4.i.i.i unwind to caller
+ cleanupret from %cleanuppadi4.i.i.i unwind to caller
}
; CHECK-LABEL: define void @f(
-; CHECK: cleanuppad []
+; CHECK: cleanuppad within none []
; CHECK-NEXT: ptrtoint i8* %phi2 to i32
define void @g() personality i32 (...)* @_except_handler3 {
@@ -63,20 +61,18 @@ throw: ; preds = %throw, %entry
pad:
%phi2 = phi i8* [ %tmp96, %throw ]
- catchpad [] to label %unreachable unwind label %blah
+ %cs = catchswitch within none [label %unreachable, label %blah] unwind to caller
unreachable:
+ catchpad within %cs []
unreachable
blah:
- %catchpad = catchpad [] to label %loop_body unwind label %blah3
-
-
-blah3:
- catchendpad unwind to caller ;label %blah2
+ %catchpad = catchpad within %cs []
+ br label %loop_body
unwind_out:
- catchret %catchpad to label %leave
+ catchret from %catchpad to label %leave
leave:
ret void
@@ -93,10 +89,7 @@ iter: ; preds = %loop_body
; CHECK-LABEL: define void @g(
; CHECK: blah:
-; CHECK-NEXT: catchpad []
-; CHECK-NEXT: to label %loop_body.preheader
-
-; CHECK: loop_body.preheader:
+; CHECK-NEXT: catchpad within %cs []
; CHECK-NEXT: ptrtoint i8* %phi2 to i32
@@ -110,29 +103,25 @@ throw: ; preds = %throw, %entry
to label %throw unwind label %pad
pad:
- catchpad [] to label %unreachable unwind label %blug
+ %cs = catchswitch within none [label %unreachable, label %blug] unwind to caller
unreachable:
+ catchpad within %cs []
unreachable
blug:
%phi2 = phi i8* [ %tmp96, %pad ]
- %catchpad = catchpad [] to label %blah2 unwind label %blah3
-
-blah2:
+ %catchpad = catchpad within %cs []
br label %loop_body
-blah3:
- catchendpad unwind to caller ;label %blah2
-
unwind_out:
- catchret %catchpad to label %leave
+ catchret from %catchpad to label %leave
leave:
ret void
loop_body: ; preds = %iter, %pad
- %tmp99 = phi i8* [ %tmp101, %iter ], [ %phi2, %blah2 ]
+ %tmp99 = phi i8* [ %tmp101, %iter ], [ %phi2, %blug ]
%tmp100 = icmp eq i8* %tmp99, undef
br i1 %tmp100, label %unwind_out, label %iter
@@ -143,10 +132,7 @@ iter: ; preds = %loop_body
; CHECK-LABEL: define void @h(
; CHECK: blug:
-; CHECK: catchpad []
-; CHECK-NEXT: to label %blah2
-
-; CHECK: blah2:
+; CHECK: catchpad within %cs []
; CHECK-NEXT: ptrtoint i8* %phi2 to i32
define void @i() personality i32 (...)* @_except_handler3 {
@@ -160,16 +146,14 @@ throw: ; preds = %throw, %entry
catchpad: ; preds = %throw
%phi2 = phi i8* [ %tmp96, %throw ]
- catchpad [] to label %cp_body unwind label %catchendpad
+ %cs = catchswitch within none [label %cp_body] unwind label %cleanuppad
cp_body:
+ catchpad within %cs []
br label %loop_head
-catchendpad:
- catchendpad unwind label %cleanuppad
-
cleanuppad:
- cleanuppad []
+ cleanuppad within none []
br label %loop_head
loop_head:
@@ -205,39 +189,31 @@ for.inc: ; preds = %for.cond
br label %for.cond
catch.dispatch: ; preds = %for.cond
- %0 = catchpad [i8* null, i32 64, i8* null]
- to label %catch unwind label %catchendblock
-
-catchendblock: ; preds = %catch.dispatch
- catchendpad unwind label %catch.dispatch.2
+ %cs = catchswitch within none [label %catch] unwind label %catch.dispatch.2
catch: ; preds = %catch.dispatch
- catchret %0 to label %try.cont
+ %0 = catchpad within %cs [i8* null, i32 64, i8* null]
+ catchret from %0 to label %try.cont
try.cont: ; preds = %catch
invoke void @external(i32* %c)
to label %try.cont.7 unwind label %catch.dispatch.2
catch.dispatch.2: ; preds = %try.cont, %catchendblock
- %e.0 = phi i32* [ %c, %try.cont ], [ %b, %catchendblock ]
- %1 = catchpad [i8* null, i32 64, i8* null]
- to label %catch.4 unwind label %catchendblock.3
+ %e.0 = phi i32* [ %c, %try.cont ], [ %b, %catch.dispatch ]
+ %cs2 = catchswitch within none [label %catch.4] unwind to caller
catch.4: ; preds = %catch.dispatch.2
+ catchpad within %cs2 [i8* null, i32 64, i8* null]
unreachable
try.cont.7: ; preds = %try.cont
ret void
-
-catchendblock.3: ; preds = %catch.dispatch.2
- catchendpad unwind to caller
}
; CHECK-LABEL: define void @test1(
; CHECK: for.cond:
; CHECK: %d.0 = phi i32* [ %b, %entry ], [ %incdec.ptr, %for.inc ]
-; CHECK: catchendpad unwind label %catch.dispatch.2
-
; CHECK: catch.dispatch.2:
-; CHECK: %e.0 = phi i32* [ %c, %try.cont ], [ %b, %catchendblock ]
+; CHECK: %e.0 = phi i32* [ %c, %try.cont ], [ %b, %catch.dispatch ]
diff --git a/test/Transforms/LoopStrengthReduce/pr25541.ll b/test/Transforms/LoopStrengthReduce/pr25541.ll
index fa64875d9af..011998b9089 100644
--- a/test/Transforms/LoopStrengthReduce/pr25541.ll
+++ b/test/Transforms/LoopStrengthReduce/pr25541.ll
@@ -12,10 +12,10 @@ for.cond.i: ; preds = %for.inc.i, %entry
to label %for.inc.i unwind label %catch.dispatch.i
catch.dispatch.i: ; preds = %for.cond.i
- %0 = catchpad [i8* null, i32 64, i8* null]
- to label %for.cond.1.preheader.i unwind label %catchendblock.i
+ %cs = catchswitch within none [label %for.cond.1.preheader.i] unwind to caller
for.cond.1.preheader.i: ; preds = %catch.dispatch.i
+ %0 = catchpad within %cs [i8* null, i32 64, i8* null]
%cmp.i = icmp eq i32* %_First.addr.0.i, null
br label %for.cond.1.i
@@ -23,18 +23,15 @@ for.cond.1.i: ; preds = %for.body.i, %for.co
br i1 %cmp.i, label %for.end.i, label %for.body.i
for.body.i: ; preds = %for.cond.1.i
- invoke void @g()
- to label %for.cond.1.i unwind label %catchendblock.i
-
-catchendblock.i: ; preds = %for.body.i, %catch.dispatch.i
- catchendpad unwind to caller
+ call void @g()
+ br label %for.cond.1.i
for.inc.i: ; preds = %for.cond.i
%incdec.ptr.i = getelementptr inbounds i32, i32* %_First.addr.0.i, i64 1
br label %for.cond.i
for.end.i: ; preds = %for.cond.1.i
- catchret %0 to label %leave
+ catchret from %0 to label %leave
leave: ; preds = %for.end.i
ret void
diff --git a/test/Transforms/LoopUnswitch/cleanuppad.ll b/test/Transforms/LoopUnswitch/cleanuppad.ll
new file mode 100644
index 00000000000..b06ebd7235c
--- /dev/null
+++ b/test/Transforms/LoopUnswitch/cleanuppad.ll
@@ -0,0 +1,44 @@
+; RUN: opt -S -loop-unswitch < %s | FileCheck %s
+target triple = "x86_64-pc-win32"
+
+define void @f(i32 %doit, i1 %x, i1 %y) personality i32 (...)* @__CxxFrameHandler3 {
+entry:
+ %tobool = icmp eq i32 %doit, 0
+ br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+ br i1 %x, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+ br i1 %tobool, label %if.then, label %for.inc
+
+if.then: ; preds = %for.body
+ br i1 %y, label %for.inc, label %delete.notnull
+
+delete.notnull: ; preds = %if.then
+ invoke void @g()
+ to label %invoke.cont unwind label %lpad
+
+invoke.cont: ; preds = %delete.notnull
+ br label %for.inc
+
+lpad: ; preds = %delete.notnull
+ %cp = cleanuppad within none []
+ cleanupret from %cp unwind to caller
+
+for.inc: ; preds = %invoke.cont, %if.then, %for.body
+ br label %for.cond
+
+for.end: ; preds = %for.cond
+ ret void
+}
+
+declare void @g()
+
+declare i32 @__CxxFrameHandler3(...)
+
+; CHECK-LABEL: define void @f(
+; CHECK: cleanuppad within none []
+; CHECK-NOT: cleanuppad
+
+attributes #0 = { ssp uwtable }
diff --git a/test/Transforms/SimplifyCFG/empty-cleanuppad.ll b/test/Transforms/SimplifyCFG/empty-cleanuppad.ll
index d04c567e503..0ba29043912 100644
--- a/test/Transforms/SimplifyCFG/empty-cleanuppad.ll
+++ b/test/Transforms/SimplifyCFG/empty-cleanuppad.ll
@@ -31,12 +31,12 @@ invoke.cont: ; preds = %entry
ret void
ehcleanup: ; preds = %entry
- %0 = cleanuppad []
- cleanupret %0 unwind label %ehcleanup.1
+ %0 = cleanuppad within none []
+ cleanupret from %0 unwind label %ehcleanup.1
ehcleanup.1: ; preds = %ehcleanup
- %1 = cleanuppad []
- cleanupret %1 unwind to caller
+ %1 = cleanuppad within none []
+ cleanupret from %1 unwind to caller
}
@@ -60,15 +60,14 @@ ehcleanup.1: ; preds = %ehcleanup
; CHECK: entry:
; CHECK: invoke void @g()
; CHECK: ehcleanup:
-; CHECK: cleanuppad
+; CHECK: cleanuppad within none
; CHECK: call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %b)
-; CHECK: cleanupret %0 unwind label %catch.dispatch
+; CHECK: cleanupret from %0 unwind label %catch.dispatch
; CHECK: catch.dispatch:
-; CHECK: catchpad
+; CHECK: catchswitch within none [label %catch] unwind to caller
; CHECK: catch:
+; CHECK: catchpad
; CHECK: catchret
-; CHECK: catchendblock: ; preds = %catch.dispatch
-; CHECK: catchendpad unwind to caller
; CHECK-NOT: cleanuppad
; CHECK: }
;
@@ -81,15 +80,16 @@ invoke.cont: ; preds = %entry
br label %try.cont
ehcleanup: ; preds = %entry
- %0 = cleanuppad []
+ %0 = cleanuppad within none []
call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %b)
- cleanupret %0 unwind label %catch.dispatch
+ cleanupret from %0 unwind label %catch.dispatch
catch.dispatch: ; preds = %ehcleanup
- %1 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock
+ %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup.1
catch: ; preds = %catch.dispatch
- catchret %1 to label %catchret.dest
+ %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
+ catchret from %1 to label %catchret.dest
catchret.dest: ; preds = %catch
br label %try.cont
@@ -97,12 +97,9 @@ catchret.dest: ; preds = %catch
try.cont: ; preds = %catchret.dest, %invoke.cont
ret void
-catchendblock: ; preds = %catch.dispatch
- catchendpad unwind label %ehcleanup.1
-
-ehcleanup.1: ; preds = %catchendblock
- %2 = cleanuppad []
- cleanupret %2 unwind to caller
+ehcleanup.1:
+ %2 = cleanuppad within none []
+ cleanupret from %2 unwind to caller
}
@@ -121,21 +118,19 @@ ehcleanup.1: ; preds = %catchendblock
; In this case the inner cleanup pad should be eliminated and the invoke of g()
; should unwind directly to the catchpad.
;
-; CHECK: define void @f3()
+; CHECK-LABEL: define void @f3()
; CHECK: entry:
; CHECK: invoke void @g()
; CHECK: to label %try.cont unwind label %catch.dispatch
; CHECK: catch.dispatch:
-; CHECK: catchpad [i8* null, i32 64, i8* null]
-; CHECK-NEXT: to label %catch unwind label %catchendblock
+; CHECK-NEXT: catchswitch within none [label %catch] unwind label %ehcleanup.1
; CHECK: catch:
+; CHECK: catchpad within %cs1 [i8* null, i32 64, i8* null]
; CHECK: catchret
-; CHECK: catchendblock:
-; CHECK: catchendpad unwind label %ehcleanup.1
; CHECK: ehcleanup.1:
; CHECK: cleanuppad
; CHECK: call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
-; CHECK: cleanupret %1 unwind to caller
+; CHECK: cleanupret from %cp3 unwind to caller
; CHECK: }
;
define void @f3() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
@@ -147,14 +142,15 @@ invoke.cont: ; preds = %entry
br label %try.cont
ehcleanup: ; preds = %entry
- %0 = cleanuppad []
- cleanupret %0 unwind label %catch.dispatch
+ %0 = cleanuppad within none []
+ cleanupret from %0 unwind label %catch.dispatch
catch.dispatch: ; preds = %ehcleanup
- %1 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock
+ %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup.1
catch: ; preds = %catch.dispatch
- catchret %1 to label %catchret.dest
+ %cp2 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
+ catchret from %cp2 to label %catchret.dest
catchret.dest: ; preds = %catch
br label %try.cont
@@ -162,13 +158,10 @@ catchret.dest: ; preds = %catch
try.cont: ; preds = %catchret.dest, %invoke.cont
ret void
-catchendblock: ; preds = %catch.dispatch
- catchendpad unwind label %ehcleanup.1
-
-ehcleanup.1: ; preds = %catchendblock
- %2 = cleanuppad []
+ehcleanup.1:
+ %cp3 = cleanuppad within none []
call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
- cleanupret %2 unwind to caller
+ cleanupret from %cp3 unwind to caller
}
@@ -184,11 +177,10 @@ ehcleanup.1: ; preds = %catchendblock
; }
;
; In this case, the cleanuppad should be eliminated, the invoke outside of the
-; call block should be converted to a call and the catchendpad should unwind
-; to the caller (that is, that is, exception handling continues with the parent
-; frame of the caller).)
+; catch block should be converted to a call (that is, that is, exception
+; handling continues with the parent frame of the caller).)
;
-; CHECK: define void @f4()
+; CHECK-LABEL: define void @f4()
; CHECK: entry:
; CHECK: call void @g
; Note: The cleanuppad simplification will insert an unconditional branch here
@@ -196,11 +188,10 @@ ehcleanup.1: ; preds = %catchendblock
; CHECK: invoke void @g()
; CHECK: to label %try.cont unwind label %catch.dispatch
; CHECK: catch.dispatch:
-; CHECK: catchpad
+; CHECK: catchswitch within none [label %catch] unwind to caller
; CHECK: catch:
+; CHECK: catchpad
; CHECK: catchret
-; CHECK: catchendblock:
-; CHECK: catchendpad unwind to caller
; CHECK-NOT: cleanuppad
; CHECK: }
;
@@ -214,43 +205,41 @@ invoke.cont: ; preds = %entry
to label %try.cont unwind label %catch.dispatch
catch.dispatch: ; preds = %invoke.cont
- %0 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock
+ %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup
catch: ; preds = %catch.dispatch
- catchret %0 to label %try.cont
+ %0 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
+ catchret from %0 to label %try.cont
try.cont: ; preds = %catch, %invoke.cont
ret void
-catchendblock: ; preds = %catch.dispatch
- catchendpad unwind label %ehcleanup
-
-ehcleanup: ; preds = %catchendblock, %entry
- %1 = cleanuppad []
- cleanupret %1 unwind to caller
+ehcleanup:
+ %cp2 = cleanuppad within none []
+ cleanupret from %cp2 unwind to caller
}
; This tests the case where a terminatepad unwinds to a cleanuppad.
; I'm not sure how this case would arise, but it seems to be syntactically
; legal so I'm testing it.
;
-; CHECK: define void @f5()
+; CHECK-LABEL: define void @f5()
; CHECK: entry:
; CHECK: invoke void @g()
; CHECK: to label %try.cont unwind label %terminate
; CHECK: terminate:
-; CHECK: terminatepad [i7 4] unwind to caller
+; CHECK: terminatepad within none [i7 4] unwind to caller
; CHECK-NOT: cleanuppad
; CHECK: try.cont:
; CHECK: invoke void @g()
; CHECK: to label %try.cont.1 unwind label %terminate.1
; CHECK: terminate.1:
-; CHECK: terminatepad [i7 4] unwind label %ehcleanup.2
+; CHECK: terminatepad within none [i7 4] unwind label %ehcleanup.2
; CHECK-NOT: ehcleanup.1:
; CHECK: ehcleanup.2:
; CHECK: [[TMP:\%.+]] = cleanuppad
; CHECK: call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
-; CHECK: cleanupret [[TMP]] unwind to caller
+; CHECK: cleanupret from [[TMP]] unwind to caller
; CHECK: }
define void @f5() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
@@ -259,27 +248,27 @@ entry:
to label %try.cont unwind label %terminate
terminate: ; preds = %entry
- terminatepad [i7 4] unwind label %ehcleanup
+ terminatepad within none [i7 4] unwind label %ehcleanup
ehcleanup: ; preds = %terminate
- %0 = cleanuppad []
- cleanupret %0 unwind to caller
+ %0 = cleanuppad within none []
+ cleanupret from %0 unwind to caller
try.cont: ; preds = %entry
invoke void @g()
to label %try.cont.1 unwind label %terminate.1
terminate.1: ; preds = %try.cont
- terminatepad [i7 4] unwind label %ehcleanup.1
+ terminatepad within none [i7 4] unwind label %ehcleanup.1
ehcleanup.1: ; preds = %terminate.1
- %1 = cleanuppad []
- cleanupret %1 unwind label %ehcleanup.2
+ %1 = cleanuppad within none []
+ cleanupret from %1 unwind label %ehcleanup.2
ehcleanup.2: ; preds = %ehcleanup.1
- %2 = cleanuppad []
+ %2 = cleanuppad within none []
call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a)
- cleanupret %2 unwind to caller
+ cleanupret from %2 unwind to caller
try.cont.1: ; preds = %try.cont
ret void
@@ -304,7 +293,7 @@ try.cont.1: ; preds = %try.cont
; In this case, the cleanup pad should be eliminated and the PHI node in the
; cleanup pad should be sunk into the catch dispatch block.
;
-; CHECK: define i32 @f6()
+; CHECK-LABEL: define i32 @f6()
; CHECK: entry:
; CHECK: invoke void @g()
; CHECK: invoke.cont:
@@ -325,17 +314,15 @@ invoke.cont: ; preds = %entry
ehcleanup: ; preds = %invoke.cont, %entry
%state.0 = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
- %0 = cleanuppad []
- cleanupret %0 unwind label %catch.dispatch
+ %0 = cleanuppad within none []
+ cleanupret from %0 unwind label %catch.dispatch
catch.dispatch: ; preds = %ehcleanup
- %1 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock
+ %cs1 = catchswitch within none [label %catch] unwind to caller
catch: ; preds = %catch.dispatch
- catchret %1 to label %return
-
-catchendblock: ; preds = %catch.dispatch
- catchendpad unwind to caller
+ %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
+ catchret from %1 to label %return
return: ; preds = %invoke.cont, %catch
%retval.0 = phi i32 [ %state.0, %catch ], [ 0, %invoke.cont ]
@@ -363,7 +350,7 @@ return: ; preds = %invoke.cont, %catch
; In this case, the cleanup pad should be eliminated and the PHI node in the
; cleanup pad should be merged with the PHI node in the catch dispatch block.
;
-; CHECK: define i32 @f7()
+; CHECK-LABEL: define i32 @f7()
; CHECK: entry:
; CHECK: invoke void @g()
; CHECK: invoke.cont:
@@ -390,18 +377,16 @@ invoke.cont.1: ; preds = %invoke.cont
ehcleanup: ; preds = %invoke.cont.1, %invoke.cont
%state.0 = phi i32 [ 3, %invoke.cont.1 ], [ 2, %invoke.cont ]
- %0 = cleanuppad []
- cleanupret %0 unwind label %catch.dispatch
+ %0 = cleanuppad within none []
+ cleanupret from %0 unwind label %catch.dispatch
catch.dispatch: ; preds = %ehcleanup, %entry
%state.1 = phi i32 [ %state.0, %ehcleanup ], [ 1, %entry ]
- %1 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock
+ %cs1 = catchswitch within none [label %catch] unwind to caller
catch: ; preds = %catch.dispatch
- catchret %1 to label %return
-
-catchendblock: ; preds = %catch.dispatch
- catchendpad unwind to caller
+ %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
+ catchret from %1 to label %return
return: ; preds = %invoke.cont.1, %catch
%retval.0 = phi i32 [ %state.1, %catch ], [ 0, %invoke.cont.1 ]
@@ -435,7 +420,7 @@ return: ; preds = %invoke.cont.1, %cat
; should have an incoming value entry for path from 'foo' that references the
; PHI node itself.
;
-; CHECK: define void @f8()
+; CHECK-LABEL: define void @f8()
; CHECK: entry:
; CHECK: invoke void @g()
; CHECK: invoke.cont:
@@ -456,18 +441,16 @@ invoke.cont: ; preds = %entry
ehcleanup: ; preds = %invoke.cont, %entry
%x = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
- %0 = cleanuppad []
- cleanupret %0 unwind label %catch.dispatch
+ %0 = cleanuppad within none []
+ cleanupret from %0 unwind label %catch.dispatch
catch.dispatch: ; preds = %ehcleanup, %catch.cont
- %1 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock
+ %cs1 = catchswitch within none [label %catch] unwind to caller
catch: ; preds = %catch.dispatch
+ %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null]
call void @use_x(i32 %x)
- catchret %1 to label %catch.cont
-
-catchendblock: ; preds = %catch.dispatch
- catchendpad unwind to caller
+ catchret from %1 to label %catch.cont
catch.cont: ; preds = %catch
invoke void @g()
diff --git a/test/Transforms/SimplifyCFG/wineh-unreachable.ll b/test/Transforms/SimplifyCFG/wineh-unreachable.ll
index 31d567f6492..aa1feb7b171 100644
--- a/test/Transforms/SimplifyCFG/wineh-unreachable.ll
+++ b/test/Transforms/SimplifyCFG/wineh-unreachable.ll
@@ -12,7 +12,7 @@ entry:
exit:
ret void
unreachable.unwind:
- cleanuppad []
+ cleanuppad within none []
unreachable
}
@@ -22,24 +22,21 @@ entry:
invoke void @f()
to label %exit unwind label %catch.pad
catch.pad:
- ; CHECK: catchpad []
- ; CHECK-NEXT: to label %catch.body unwind label %catch.end
- %catch = catchpad []
- to label %catch.body unwind label %catch.end
+ %cs1 = catchswitch within none [label %catch.body] unwind label %unreachable.unwind
+ ; CHECK: catch.pad:
+ ; CHECK-NEXT: catchswitch within none [label %catch.body] unwind to caller
catch.body:
; CHECK: catch.body:
+ ; CHECK-NEXT: catchpad within %cs1
; CHECK-NEXT: call void @f()
; CHECK-NEXT: unreachable
+ %catch = catchpad within %cs1 []
call void @f()
- catchret %catch to label %unreachable
-catch.end:
- ; CHECK: catch.end:
- ; CHECK-NEXT: catchendpad unwind to caller
- catchendpad unwind label %unreachable.unwind
+ catchret from %catch to label %unreachable
exit:
ret void
unreachable.unwind:
- cleanuppad []
+ cleanuppad within none []
unreachable
unreachable:
unreachable
@@ -51,24 +48,20 @@ entry:
invoke void @f()
to label %exit unwind label %cleanup.pad
cleanup.pad:
- ; CHECK: %cleanup = cleanuppad []
+ ; CHECK: %cleanup = cleanuppad within none []
; CHECK-NEXT: call void @f()
; CHECK-NEXT: unreachable
- %cleanup = cleanuppad []
+ %cleanup = cleanuppad within none []
invoke void @f()
- to label %cleanup.ret unwind label %cleanup.end
+ to label %cleanup.ret unwind label %unreachable.unwind
cleanup.ret:
; This cleanupret should be rewritten to unreachable,
; and merged into the pred block.
- cleanupret %cleanup unwind label %unreachable.unwind
-cleanup.end:
- ; This cleanupendpad should be rewritten to unreachable,
- ; causing the invoke to be rewritten to a call.
- cleanupendpad %cleanup unwind label %unreachable.unwind
+ cleanupret from %cleanup unwind label %unreachable.unwind
exit:
ret void
unreachable.unwind:
- cleanuppad []
+ cleanuppad within none []
unreachable
}
@@ -78,12 +71,12 @@ entry:
invoke void @f()
to label %exit unwind label %terminate.pad
terminate.pad:
- ; CHECK: terminatepad [] unwind to caller
- terminatepad [] unwind label %unreachable.unwind
+ ; CHECK: terminatepad within none [] unwind to caller
+ terminatepad within none [] unwind label %unreachable.unwind
exit:
ret void
unreachable.unwind:
- cleanuppad []
+ cleanuppad within none []
unreachable
}
@@ -94,14 +87,11 @@ entry:
to label %exit unwind label %catch.pad
catch.pad:
- %catch = catchpad []
- to label %catch.body unwind label %catch.end
+ %cs1 = catchswitch within none [label %catch.body] unwind to caller
catch.body:
- catchret %catch to label %exit
-
-catch.end:
- catchendpad unwind to caller
+ %catch = catchpad within %cs1 []
+ catchret from %catch to label %exit
exit:
unreachable
diff --git a/test/Transforms/Sink/catchswitch.ll b/test/Transforms/Sink/catchswitch.ll
new file mode 100644
index 00000000000..2648f85f3eb
--- /dev/null
+++ b/test/Transforms/Sink/catchswitch.ll
@@ -0,0 +1,37 @@
+; RUN: opt -sink -S < %s | FileCheck %s
+
+target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
+target triple = "i686-pc-windows-msvc"
+
+define void @h() personality i32 (...)* @__CxxFrameHandler3 {
+entry:
+ %call = call i32 @g(i32 1) readnone
+ invoke void @_CxxThrowException(i8* null, i8* null) noreturn
+ to label %unreachable unwind label %catch.dispatch
+
+catch.dispatch: ; preds = %entry
+ %cs = catchswitch within none [label %catch] unwind to caller
+
+catch: ; preds = %catch.dispatch
+ %cp = catchpad within %cs [i8* null, i32 64, i8* null]
+ catchret from %cp to label %try.cont
+
+try.cont: ; preds = %catch
+ call void @k(i32 %call)
+ ret void
+
+unreachable: ; preds = %entry
+ unreachable
+}
+
+declare x86_stdcallcc void @_CxxThrowException(i8*, i8*)
+
+declare i32 @__CxxFrameHandler3(...)
+
+declare i32 @g(i32) readnone
+
+declare void @k(i32)
+
+; CHECK-LABEL: define void @h(
+; CHECK: call i32 @g(i32 1)
+; CHECK-NEXT: invoke void @_CxxThrowException(
diff --git a/test/Verifier/invalid-eh.ll b/test/Verifier/invalid-eh.ll
new file mode 100644
index 00000000000..906b24a15c3
--- /dev/null
+++ b/test/Verifier/invalid-eh.ll
@@ -0,0 +1,38 @@
+; RUN: sed -e s/.T1:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK1 %s
+; RUN: sed -e s/.T2:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK2 %s
+; RUN: sed -e s/.T3:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK3 %s
+; RUN: sed -e s/.T4:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK4 %s
+
+;T1: define void @f() {
+;T1: entry:
+;T1: catchret from undef to label %next
+;T1: ; CHECK1: CatchReturnInst needs to be provided a CatchPad
+;T1: next:
+;T1: unreachable
+;T1: }
+
+;T2: define void @f() {
+;T2: entry:
+;T2: %x = cleanuppad within none []
+;T2: ; catchret's first operand's operator must be catchpad
+;T2: catchret from %x to label %entry
+;T2: ; CHECK2: CatchReturnInst needs to be provided a CatchPad
+;T2: }
+
+;T3: define void @f() {
+;T3: entry:
+;T3: cleanupret from undef unwind label %next
+;T3: ; CHECK3: CleanupReturnInst needs to be provided a CleanupPad
+;T3: next:
+;T3: unreachable
+;T3: }
+
+;T4: define void @f() {
+;T4: entry:
+;T4: %cs = catchswitch within none [label %next] unwind to caller
+;T4: next:
+;T4: %x = catchpad within %cs []
+;T4: ; cleanupret first operand's operator must be cleanuppad
+;T4: cleanupret from %x unwind to caller
+;T4: ; CHECK4: CleanupReturnInst needs to be provided a CleanupPad
+;T4: }
diff --git a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
index f08b0c4cbc0..11ca59f8459 100644
--- a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
+++ b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
@@ -259,8 +259,6 @@ 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_CLEANUPENDPAD)
- STRINGIFY_CODE(FUNC_CODE, INST_CATCHENDPAD)
STRINGIFY_CODE(FUNC_CODE, INST_TERMINATEPAD)
STRINGIFY_CODE(FUNC_CODE, INST_PHI)
STRINGIFY_CODE(FUNC_CODE, INST_ALLOCA)