[IR] Reformulate LLVM's EH funclet IR

While we have successfully implemented a funclet-oriented EH scheme on
top of LLVM IR, our scheme has some notable deficiencies:
- catchendpad and cleanupendpad are necessary in the current design
  but they are difficult to explain to others, even to seasoned LLVM
  experts.
- catchendpad and cleanupendpad are optimization barriers.  They cannot
  be split and force all potentially throwing call-sites to be invokes.
  This has a noticable effect on the quality of our code generation.
- catchpad, while similar in some aspects to invoke, is fairly awkward.
  It is unsplittable, starts a funclet, and has control flow to other
  funclets.
- The nesting relationship between funclets is currently a property of
  control flow edges.  Because of this, we are forced to carefully
  analyze the flow graph to see if there might potentially exist illegal
  nesting among funclets.  While we have logic to clone funclets when
  they are illegally nested, it would be nicer if we had a
  representation which forbade them upfront.

Let's clean this up a bit by doing the following:
- Instead, make catchpad more like cleanuppad and landingpad: no control
  flow, just a bunch of simple operands;  catchpad would be splittable.
- Introduce catchswitch, a control flow instruction designed to model
  the constraints of funclet oriented EH.
- Make funclet scoping explicit by having funclet instructions consume
  the token produced by the funclet which contains them.
- Remove catchendpad and cleanupendpad.  Their presence can be inferred
  implicitly using coloring information.

N.B.  The state numbering code for the CLR has been updated but the
veracity of it's output cannot be spoken for.  An expert should take a
look to make sure the results are reasonable.

Reviewers: rnk, JosephTremoulet, andrew.w.kaylor

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

llvm-svn: 255422
This commit is contained in:
David Majnemer 2015-12-12 05:38:55 +00:00
parent a38312a9a4
commit 8a1c45d6e8
106 changed files with 3135 additions and 6143 deletions

View File

@ -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.
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 ``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.
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.2
%0 = cleanuppad within none []
call void @"\01??1Cleanup@@QEAA@XZ"(%struct.Cleanup* nonnull %obj) nounwind
cleanupret %0 unwind label %lpad.catch
lpad.cleanup: ; preds = %invoke.cont
%cleanup = cleanuppad []
call void @"\01??_DCleanup@@QEAA@XZ"(%struct.Cleanup* nonnull %obj) nounwind
cleanupret %cleanup 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
catchend: ; preds = %lpad.catch, %catch.body
catchendpad unwind label %lpad.terminate
lpad.terminate: ; preds = %catchend
terminatepad [void ()* @"\01?terminate@@YAXXZ"]
unwind to caller
lpad.terminate: ; preds = %catch.body, %lpad.catch
terminatepad within none [void ()* @"\01?terminate@@YAXXZ"] unwind to caller
}
Funclet parent tokens
-----------------------
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.
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.

View File

@ -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,6 +5360,61 @@ Example:
resume { i8*, i32 } %exn
.. _i_catchswitch:
'``catchswitch``' Instruction
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Syntax:
"""""""
::
<resultval> = catchswitch within <parent> [ label <handler1>, label <handler2>, ... ] unwind to caller
<resultval> = catchswitch within <parent> [ label <handler1>, label <handler2>, ... ] unwind label <default>
Overview:
"""""""""
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 ``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 ``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:
""""""""""
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 ``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
dispatch1:
%cs1 = catchswitch within none [label %handler0, label %handler1] unwind to caller
dispatch2:
%cs2 = catchswitch within %parenthandler [label %handler0] unwind label %cleanup
.. _i_catchpad:
'``catchpad``' Instruction
@ -5372,155 +5425,70 @@ Syntax:
::
<resultval> = catchpad [<args>*]
to label <normal label> unwind label <exception label>
<resultval> = catchpad within <catchswitch> [<args>*]
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
begins a catch handler --- 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>`.
Arguments:
""""""""""
The instruction takes a list of arbitrary values which are interpreted
by the :ref:`personality function <personalityfn>`.
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 ``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 ``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,
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.
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 ``catchpad`` 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 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 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
dispatch:
%cs = catchswitch within none [label %handler0] unwind to caller
;; A catch block which can catch an integer.
%tok = catchpad [i8** @_ZTIi]
to label %int.handler unwind label %terminate
.. _i_catchendpad:
'``catchendpad``' Instruction
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Syntax:
"""""""
::
catchendpad unwind label <nextaction>
catchendpad unwind to caller
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.
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.
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.
The ``catchendpad`` instruction has several restrictions:
- 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.
Example:
""""""""
.. code-block:: llvm
catchendpad unwind label %terminate
catchendpad unwind to caller
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.
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``.
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.
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
catchret %catch label %continue
.. _i_cleanupendpad:
'``cleanupendpad``' Instruction
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Syntax:
"""""""
::
cleanupendpad <value> unwind label <nextaction>
cleanupendpad <value> unwind to caller
Overview:
"""""""""
The '``cleanupendpad``' instruction is used by `LLVM's exception handling
system <ExceptionHandling.html#overview>`_ to communicate to the
:ref:`personality function <personalityfn>` which invokes are associated
with a :ref:`cleanuppad <i_cleanuppad>` instructions; propagating an exception
out of a cleanup is represented by unwinding through its ``cleanupendpad``.
The ``nextaction`` label indicates where control should unwind to next, in the
event that a cleanup is exited by means of an(other) exception being raised.
If a ``nextaction`` label is not present, the instruction unwinds out of
its parent function. The
:ref:`personality function <personalityfn>` will continue processing
exception handling actions in the caller.
Arguments:
""""""""""
The '``cleanupendpad``' instruction requires one argument, which indicates
which ``cleanuppad`` it exits, and must be a :ref:`cleanuppad <i_cleanuppad>`.
It also has an optional successor, ``nextaction``, indicating where control
should transfer to.
Semantics:
""""""""""
When and exception propagates to a ``cleanupendpad``, control is transfered to
``nextaction`` if it is present. If it is not present, control is transfered to
the caller.
The ``cleanupendpad`` instruction has several restrictions:
- A cleanup-end block is a basic block which is the unwind destination of
an exceptional instruction.
- A cleanup-end block must have a '``cleanupendpad``' instruction as its
first non-PHI instruction.
- There can be only one '``cleanupendpad``' instruction within the
cleanup-end block.
- A basic block that is not a cleanup-end block may not include a
'``cleanupendpad``' instruction.
- It is undefined behavior to execute a ``cleanupendpad`` whose ``cleanuppad``
has not been executed.
- It is undefined behavior to execute a ``cleanupendpad`` if, after the most
recent execution of its ``cleanuppad``, some ``cleanupret`` or ``cleanupendpad``
consuming the same ``cleanuppad`` has already been executed.
- It is undefined behavior to execute a ``cleanupendpad`` if, after the most
recent execution of its ``cleanuppad``, any other ``cleanuppad`` or
``catchpad`` has been executed but has not had a corresponding
``cleanupret``/``catchret``/``cleanupendpad``/``catchendpad`` executed.
Example:
""""""""
.. code-block:: llvm
cleanupendpad %cleanup unwind label %terminate
cleanupendpad %cleanup unwind to caller
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:

View File

@ -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) \

View File

@ -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

View File

@ -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...]
};

View File

@ -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;

View File

@ -708,29 +708,29 @@ public:
return Insert(CleanupReturnInst::Create(CleanupPad, UnwindBB));
}
CleanupEndPadInst *CreateCleanupEndPad(CleanupPadInst *CleanupPad,
BasicBlock *UnwindBB = nullptr) {
return Insert(CleanupEndPadInst::Create(CleanupPad, UnwindBB));
CatchSwitchInst *CreateCatchSwitch(Value *ParentPad, BasicBlock *UnwindBB,
unsigned NumHandlers,
const Twine &Name = "") {
return Insert(CatchSwitchInst::Create(ParentPad, UnwindBB, NumHandlers),
Name);
}
CatchPadInst *CreateCatchPad(BasicBlock *NormalDest, BasicBlock *UnwindDest,
ArrayRef<Value *> Args, const Twine &Name = "") {
return Insert(CatchPadInst::Create(NormalDest, UnwindDest, Args), Name);
CatchPadInst *CreateCatchPad(Value *ParentPad, ArrayRef<Value *> Args,
const Twine &Name = "") {
return Insert(CatchPadInst::Create(ParentPad, Args), Name);
}
CatchEndPadInst *CreateCatchEndPad(BasicBlock *UnwindBB = nullptr) {
return Insert(CatchEndPadInst::Create(Context, UnwindBB));
}
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) {

View File

@ -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);}

View File

@ -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 {

View File

@ -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

View File

@ -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,

View File

@ -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,56 +3820,161 @@ 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);
}
/// 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:
static BasicBlock *handler_helper(Value *V) { return cast<BasicBlock>(V); }
static const BasicBlock *handler_helper(const Value *V) {
return cast<BasicBlock>(V);
}
public:
typedef std::pointer_to_unary_function<Value *, BasicBlock *> DerefFnTy;
typedef mapped_iterator<op_iterator, DerefFnTy> handler_iterator;
typedef iterator_range<handler_iterator> handler_range;
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;
/// 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));
}
/// 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));
}
/// handlers - iteration adapter for range-for loops.
handler_range handlers() {
return make_range(handler_begin(), handler_end());
}
/// handlers - iteration adapter for range-for loops.
const_handler_range handlers() const {
return make_range(handler_begin(), handler_end());
}
/// 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);
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 < getNumSuccessors() &&
"Successor # out of range for catchswitch!");
setOperand(Idx + 1, NewSucc);
}
// Methods for support type inquiry through isa, cast, and dyn_cast:
static inline bool classof(const Instruction *I) {
return (I->getOpcode() == Instruction::CatchEndPad);
return I->getOpcode() == Instruction::CatchSwitch;
}
static inline bool classof(const Value *V) {
return isa<Instruction>(V) && classof(cast<Instruction>(V));
@ -3878,122 +3984,12 @@ 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<CatchEndPadInst>
: public VariadicOperandTraits<CatchEndPadInst> {};
struct OperandTraits<CatchSwitchInst> : public HungoffOperandTraits<2> {};
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);
}
/// Provide fast operand accessors
DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
/// getNumArgOperands - Return the number of catchpad arguments.
///
unsigned getNumArgOperands() const { return getNumOperands() - 2; }
/// 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); }
/// arg_operands - iteration adapter for range-for loops.
iterator_range<op_iterator> arg_operands() {
return make_range(op_begin(), op_end() - 2);
}
/// arg_operands - iteration adapter for range-for loops.
iterator_range<const_op_iterator> arg_operands() const {
return make_range(op_begin(), op_end() - 2);
}
/// \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); }
// 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; }
BasicBlock *getSuccessor(unsigned i) const {
assert(i < 2 && "Successor # out of range for catchpad!");
return i == 0 ? getNormalDest() : getUnwindDest();
}
void setSuccessor(unsigned idx, BasicBlock *NewSucc) {
assert(idx < 2 && "Successor # out of range for catchpad!");
*(&Op<-2>() + idx) = 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;
}
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;
};
template <>
struct OperandTraits<CatchPadInst>
: public VariadicOperandTraits<CatchPadInst, /*MINARITY=*/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);
@ -4238,93 +4288,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:

View File

@ -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.

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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)) {

View File

@ -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!");

View File

@ -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

View File

@ -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) \

View File

@ -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,31 +5208,98 @@ 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;
}
/// 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;
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;
if (ParseToken(lltok::lsquare, "expected '[' with catchswitch labels"))
return true;
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' after catchswitch scope"))
return true;
BasicBlock *UnwindBB = nullptr;
if (EatIfPresent(lltok::kw_to)) {
if (ParseToken(lltok::kw_caller, "expected 'caller' in catchswitch"))
return true;
} else {
if (ParseTypeAndBasicBlock(UnwindBB, PFS))
return true;
}
auto *CatchSwitch =
CatchSwitchInst::Create(ParentPad, UnwindBB, Table.size());
for (BasicBlock *DestBB : Table)
CatchSwitch->addHandler(DestBB);
Inst = CatchSwitch;
return false;
}
/// 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;
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))
return true;
Inst = CatchPadInst::Create(NormalBB, UnwindBB, Args);
Inst = CatchPadInst::Create(CatchSwitch, Args);
return false;
}
/// ParseTerminatePad
/// ::= 'terminatepad' ParamList 'to' TypeAndValue
/// ::= '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;
@ -5343,71 +5318,30 @@ bool LLParser::ParseTerminatePad(Instruction *&Inst, PerFunctionState &PFS) {
}
}
Inst = TerminatePadInst::Create(Context, UnwindBB, Args);
Inst = TerminatePadInst::Create(ParentPad, UnwindBB, Args);
return false;
}
/// ParseCleanupPad
/// ::= 'cleanuppad' ParamList
/// ::= 'cleanuppad' within Parent ParamList
bool LLParser::ParseCleanupPad(Instruction *&Inst, PerFunctionState &PFS) {
Value *ParentPad = nullptr;
if (ParseToken(lltok::kw_within, "expected 'within' after cleanuppad"))
return true;
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;
SmallVector<Value *, 8> Args;
if (ParseExceptionArgs(Args, PFS))
return true;
Inst = CleanupPadInst::Create(Context, 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"))
return true;
BasicBlock *UnwindBB = nullptr;
if (Lex.getKind() == lltok::kw_to) {
Lex.Lex();
if (Lex.getKind() == lltok::kw_caller) {
Lex.Lex();
} else {
return true;
}
} else {
if (ParseTypeAndBasicBlock(UnwindBB, PFS)) {
return true;
}
}
Inst = CatchEndPadInst::Create(Context, UnwindBB);
return false;
}
/// ParseCatchEndPad
/// ::= 'cleanupendpad' Value unwind ('to' 'caller' | TypeAndValue)
bool LLParser::ParseCleanupEndPad(Instruction *&Inst, PerFunctionState &PFS) {
Value *CleanupPad = nullptr;
if (ParseValue(Type::getTokenTy(Context), CleanupPad, PFS, OC_CleanupPad))
return true;
if (ParseToken(lltok::kw_unwind, "expected 'unwind' in catchendpad"))
return true;
BasicBlock *UnwindBB = nullptr;
if (Lex.getKind() == lltok::kw_to) {
Lex.Lex();
if (Lex.getKind() == lltok::kw_caller) {
Lex.Lex();
} else {
return true;
}
} else {
if (ParseTypeAndBasicBlock(UnwindBB, PFS)) {
return true;
}
}
Inst = CleanupEndPadInst::Create(cast<CleanupPadInst>(CleanupPad), UnwindBB);
Inst = CleanupPadInst::Create(ParentPad, Args);
return false;
}

View File

@ -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);

View File

@ -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,

View File

@ -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)
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))
return error("Invalid record");
Args.push_back(Val);
}
if (Record.size() != Idx)
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");
I = CatchPadInst::Create(NormalBB, UnwindBB, Args);
InstructionList.push_back(I);
break;
}
case bitc::FUNC_CODE_INST_TERMINATEPAD: { // TERMINATEPAD: [bb#,num,(ty,val)*]
if (Record.size() < 1)
return error("Invalid record");
unsigned Idx = 0;
bool HasUnwindDest = !!Record[Idx++];
BasicBlock *UnwindDest = nullptr;
if (HasUnwindDest) {
if (Idx == Record.size())
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");
}
if (Record.size() != Idx)
return error("Invalid record");
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: [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;
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)
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:

View File

@ -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:

View File

@ -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.
}
}
}

View File

@ -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");
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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)) {

View File

@ -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.

View File

@ -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);

View File

@ -763,61 +763,6 @@ BasicBlock *ResumeInst::getSuccessorV(unsigned idx) const {
llvm_unreachable("ResumeInst has no successors!");
}
//===----------------------------------------------------------------------===//
// CleanupEndPadInst Implementation
//===----------------------------------------------------------------------===//
CleanupEndPadInst::CleanupEndPadInst(const CleanupEndPadInst &CEPI)
: TerminatorInst(CEPI.getType(), Instruction::CleanupEndPad,
OperandTraits<CleanupEndPadInst>::op_end(this) -
CEPI.getNumOperands(),
CEPI.getNumOperands()) {
setInstructionSubclassData(CEPI.getSubclassDataFromInstruction());
setCleanupPad(CEPI.getCleanupPad());
if (BasicBlock *UnwindDest = CEPI.getUnwindDest())
setUnwindDest(UnwindDest);
}
void CleanupEndPadInst::init(CleanupPadInst *CleanupPad, BasicBlock *UnwindBB) {
setCleanupPad(CleanupPad);
if (UnwindBB) {
setInstructionSubclassData(getSubclassDataFromInstruction() | 1);
setUnwindDest(UnwindBB);
}
}
CleanupEndPadInst::CleanupEndPadInst(CleanupPadInst *CleanupPad,
BasicBlock *UnwindBB, unsigned Values,
Instruction *InsertBefore)
: TerminatorInst(Type::getVoidTy(CleanupPad->getContext()),
Instruction::CleanupEndPad,
OperandTraits<CleanupEndPadInst>::op_end(this) - Values,
Values, InsertBefore) {
init(CleanupPad, UnwindBB);
}
CleanupEndPadInst::CleanupEndPadInst(CleanupPadInst *CleanupPad,
BasicBlock *UnwindBB, unsigned Values,
BasicBlock *InsertAtEnd)
: TerminatorInst(Type::getVoidTy(CleanupPad->getContext()),
Instruction::CleanupEndPad,
OperandTraits<CleanupEndPadInst>::op_end(this) - Values,
Values, InsertAtEnd) {
init(CleanupPad, UnwindBB);
}
BasicBlock *CleanupEndPadInst::getSuccessorV(unsigned Idx) const {
assert(Idx == 0);
return getUnwindDest();
}
unsigned CleanupEndPadInst::getNumSuccessorsV() const {
return getNumSuccessors();
}
void CleanupEndPadInst::setSuccessorV(unsigned Idx, BasicBlock *B) {
assert(Idx == 0);
setUnwindDest(B);
}
//===----------------------------------------------------------------------===//
// CleanupReturnInst Implementation
//===----------------------------------------------------------------------===//
@ -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,
@ -874,59 +817,10 @@ void CleanupReturnInst::setSuccessorV(unsigned Idx, BasicBlock *B) {
setUnwindDest(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());
}
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);
}
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,
CatchSwitchInst::CatchSwitchInst(Value *ParentPad, BasicBlock *UnwindDest,
unsigned NumReservedValues,
const Twine &NameStr, BasicBlock *InsertAtEnd)
: TerminatorInst(ParentPad->getType(), Instruction::CatchSwitch, nullptr, 0,
InsertAtEnd) {
init(IfNormal, IfException, Args, NameStr);
if (UnwindDest)
++NumReservedValues;
init(ParentPad, UnwindDest, NumReservedValues + 1);
setName(NameStr);
}
BasicBlock *CatchPadInst::getSuccessorV(unsigned Idx) const {
return getSuccessor(Idx);
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];
}
unsigned CatchPadInst::getNumSuccessorsV() const {
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);
}
}
/// 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 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 {
@ -1066,39 +1034,6 @@ void TerminatePadInst::setSuccessorV(unsigned Idx, BasicBlock *B) {
return setUnwindDest(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,34 +4009,26 @@ 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);
}
FuncletPadInst *FuncletPadInst::cloneImpl() const {
return new (getNumOperands()) FuncletPadInst(*this);
}
TerminatePadInst *TerminatePadInst::cloneImpl() const {
return new (getNumOperands()) TerminatePadInst(*this);
}
CleanupPadInst *CleanupPadInst::cloneImpl() const {
return new (getNumOperands()) CleanupPadInst(*this);
}
UnreachableInst *UnreachableInst::cloneImpl() const {
LLVMContext &Context = getContext();
return new UnreachableInst(Context);

View File

@ -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);
void Verifier::visitCatchReturnInst(CatchReturnInst &CatchReturn) {
Assert(isa<CatchPadInst>(CatchReturn.getOperand(0)),
"CatchReturnInst needs to be provided a CatchPad", &CatchReturn,
CatchReturn.getOperand(0));
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);
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);
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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.

View File

@ -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;

View File

@ -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)) {

View File

@ -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);

View File

@ -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();
}

View File

@ -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.

View File

@ -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: }

View File

@ -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
catchswitch2:
%cs2 = catchswitch within none [label %catchpad2] unwind to caller
catchpad2:
catchpad [i32* %arg1] to label %normal unwind label %exn.2
; CHECK: catchpad [i32* %arg1]
; CHECK-NEXT: to label %normal unwind label %exn.2
catchpad within %cs2 [i32* %arg1]
br label %normal
; CHECK: catchpad within %cs2 [i32* %arg1]
; CHECK-NEXT: br label %normal
catchswitch3:
%cs3 = catchswitch within none [label %catchpad3] unwind label %cleanuppad1
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
exn.2:
catchendpad unwind to caller
; CHECK: catchendpad unwind to caller
exn.3:
catchendpad unwind label %cleanuppad1
; CHECK: catchendpad unwind label %cleanuppad1
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

View File

@ -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,52 +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: 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 @test7() personality i32 (...)* @__CxxFrameHandler3 {
define void @test9() personality i32 (...)* @__C_specific_handler {
entry:
invoke void @f()
to label %invoke.cont unwind label %left
@ -312,176 +286,32 @@ 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: unreachable
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 []
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

View File

@ -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
}

View File

@ -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
}

File diff suppressed because it is too large Load Diff

View File

@ -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()

View File

@ -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
}

View File

@ -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
; CHECK: call void @g(i32 1)
call void @g(i32 1)
catchret from %2 to label %try.cont
invoke.cont: ; preds = %catch.3
catchret %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

View File

@ -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 ]

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
ehcleanup.end: ; preds = %ehcleanup
cleanupendpad %1 unwind label %catch.dispatch.7
__except: ; preds = %catch.dispatch
%cp1 = catchpad within %cs1 [i8* null]
catchret from %cp1 to label %__except.2
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)

View File

@ -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:

View File

@ -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

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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
outer.catch:
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
outer.ret:
catchret %outer to label %exit
outer.end:
catchendpad unwind to caller
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 %catch.dispatch.2
outer.ret:
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

View File

@ -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 ]

View File

@ -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

View File

@ -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:

View File

@ -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)

View File

@ -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]]

View File

@ -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
invoke.cont.10:
catchret %p2 to label %try.cont.9
eh.resume: ; preds = %catch.dispatch.4
catchendpad unwind to caller
%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
}
; CHECK-LABEL: _f:
; CHECK: movl $-1, [[state:[-0-9]+]](%ebp)
; CHECK: movl $___ehhandler$f, {{.*}}
; X86-LABEL: _f:
; X86: movl $-1, [[state:[-0-9]+]](%ebp)
; X86: movl $___ehhandler$f, {{.*}}
;
; CHECK: movl $0, [[state]](%ebp)
; CHECK: movl $1, (%esp)
; CHECK: calll _may_throw
; X86: movl $0, [[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 $1, [[state]](%ebp)
; X86: movl $2, (%esp)
; X86: calll _may_throw
;
; CHECK: movl $2, [[state]](%ebp)
; CHECK: movl $3, (%esp)
; CHECK: calll _may_throw
; X86: movl $2, [[state]](%ebp)
; X86: movl $3, (%esp)
; X86: calll _may_throw
;
; CHECK: movl $3, [[state]](%ebp)
; CHECK: movl $4, (%esp)
; CHECK: calll _may_throw
; X86: movl $3, [[state]](%ebp)
; X86: movl $4, (%esp)
; X86: calll _may_throw
; CHECK: .safeseh ___ehhandler$f
; 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);
; }
; }
%struct.S = type { i8 }
declare void @"\01??1S@@QEAA@XZ"(%struct.S*)
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
}
; X86-LABEL: _g:
; X86: movl $-1, [[state:[-0-9]+]](%ebp)
; X86: movl $___ehhandler$g, {{.*}}
;
; X86: movl $1, [[state]](%ebp)
; X86: movl $-1, (%esp)
; X86: calll _may_throw
;
; X86: movl $2, [[state]](%ebp)
; X86: movl $0, (%esp)
; X86: calll _may_throw
;
; X86: movl $3, [[state]](%ebp)
; X86: movl $1, (%esp)
; X86: calll _may_throw
;
; 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

View File

@ -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:

View File

@ -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.

View File

@ -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 _nested_exceptions_filter_catchall
; CHECK: .long LBB
; CHECK: .long 1
; CHECK: .long _nested_exceptions_filter_catchall
; CHECK: .long LBB
; CHECK: .long -1
; CHECK: .long _nested_exceptions_filter_catchall
; CHECK: .long LBB
; CHECK: .long 2
; CHECK: .long _nested_exceptions_filter_catchall
; CHECK: .long LBB
; CHECK: .long 3
; 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)

View File

@ -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

View File

@ -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)

View File

@ -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
}

View File

@ -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
}

View File

@ -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
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*
catch2:
%cp2 = catchpad [] to label %catch.dispatch unwind label %catchend2
%cs2 = catchswitch within none [label %handler2] unwind to caller
; CHECK: catch.dispatch:
; CHECK-NEXT: %p = phi i8* [ %p1, %catch1 ], [ %p2, %catch2 ]
catch.dispatch:
%p = phi i8* [ %p1, %catch1 ], [ %p2, %catch2 ]
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}

View File

@ -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
}

View File

@ -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
}

View File

@ -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()

View File

@ -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(

View File

@ -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 ]

View File

@ -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

Some files were not shown because too many files have changed in this diff Show More