Index: docs/ExceptionHandling.rst =================================================================== --- docs/ExceptionHandling.rst +++ docs/ExceptionHandling.rst @@ -522,16 +522,12 @@ 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 @@ 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 @@ executes a ``catchret`` instruction, which is a terminator indicating where in the function control is returned to. A cleanup handler which reaches its end by normal execution executes a ``cleanupret`` instruction, which is a terminator -indicating where the active exception will unwind to next. A catch or cleanup -handler which is exited by another exception being raised during its execution will -unwind through a ``catchendpad`` or ``cleanuupendpad`` (respectively). The -``catchendpad`` and ``cleanupendpad`` instructions are considered "exception -handling pads" in the same sense that ``catchpad``, ``cleanuppad``, and -``terminatepad`` are. - -Each of these new EH pad instructions has a way to identify which -action should be considered after this action. The ``catchpad`` and -``terminatepad`` instructions are terminators, and have a label operand considered -to be an unwind destination analogous to the unwind destination of an invoke. The -``cleanuppad`` instruction is different from the other two in that it is not a -terminator. The code inside a cleanuppad runs before transferring control to the -next action, so the ``cleanupret`` and ``cleanupendpad`` instructions are the -instructions that hold a label operand and unwind to the next EH pad. All of -these "unwind edges" may refer to a basic block that contains an EH pad instruction, -or they may simply unwind to the caller. Unwinding to the caller has roughly the -same semantics as the ``resume`` instruction in the ``landingpad`` model. When -inlining through an invoke, instructions that unwind to the caller are hooked -up to unwind to the unwind destination of the call site. +indicating where the active exception will unwind to next. + +Each of these new EH pad instructions has a way to identify which action should +be considered after this action. The ``catchswitch`` and ``terminatepad`` +instructions are terminators, and have a unwind destination operand analogous +to the unwind destination of an invoke. The ``cleanuppad`` instruction is not +a terminator, so the unwind destination is stored on the ``cleanupret`` +instruction instead. Successfully executing a catch handler should resume +normal control flow, so neither ``catchpad`` nor ``catchret`` instructions can +unwind. All of these "unwind edges" may refer to a basic block that contains an +EH pad instruction, or they may unwind to the caller. Unwinding to the caller +has roughly the same semantics as the ``resume`` instruction in the landingpad +model. When inlining through an invoke, instructions that unwind to the caller +are hooked up to unwind to the unwind destination of the call site. Putting things together, here is a hypothetical lowering of some C++ that uses all of the new IR instructions: @@ -694,33 +685,95 @@ call void @"\01??_DCleanup@@QEAA@XZ"(%struct.Cleanup* nonnull %obj) nounwind br label %return - return: ; preds = %invoke.cont.2, %invoke.cont.3 - %retval.0 = phi i32 [ 0, %invoke.cont.2 ], [ %9, %catch ] + return: ; preds = %invoke.cont.3, %invoke.cont.2 + %retval.0 = phi i32 [ 0, %invoke.cont.2 ], [ %3, %invoke.cont.3 ] ret i32 %retval.0 - ; EH scope code, ordered innermost to outermost: - - lpad.cleanup: ; preds = %invoke.cont - %cleanup = cleanuppad [] - call void @"\01??_DCleanup@@QEAA@XZ"(%struct.Cleanup* nonnull %obj) nounwind - cleanupret %cleanup unwind label %lpad.catch + lpad.cleanup: ; preds = %invoke.cont.2 + %0 = cleanuppad within none [] + call void @"\01??1Cleanup@@QEAA@XZ"(%struct.Cleanup* nonnull %obj) nounwind + cleanupret %0 unwind label %lpad.catch - lpad.catch: ; preds = %entry, %lpad.cleanup - %catch = catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i32* %e] - to label %catch.body unwind label %catchend + lpad.catch: ; preds = %lpad.cleanup, %entry + %1 = catchswitch within none [label %catch.body] unwind label %lpad.terminate catch.body: ; preds = %lpad.catch + %catch = catchpad within %1 [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i32* %e] invoke void @"\01?may_throw@@YAXXZ"() - to label %invoke.cont.3 unwind label %catchend + to label %invoke.cont.3 unwind label %lpad.terminate invoke.cont.3: ; preds = %catch.body - %9 = load i32, i32* %e, align 4 - catchret %catch to label %return + %3 = load i32, i32* %e, align 4 + catchret from %catch to label %return + + lpad.terminate: ; preds = %catch.body, %lpad.catch + terminatepad within none [void ()* @"\01?terminate@@YAXXZ"] unwind to caller + } + +Funclet parent tokens +----------------------- - catchend: ; preds = %lpad.catch, %catch.body - catchendpad unwind label %lpad.terminate +In order to produce tables for EH personalities that use funclets, it is +necessary to recover the nesting that was present in the source. This funclet +parent relationship is encoded in the IR using tokens produced by the new "pad" +instructions. The token operand of a "pad" or "ret" instruction indicates which +funclet it is in, or "none" if it is not nested within another funclet. - lpad.terminate: ; preds = %catchend - terminatepad [void ()* @"\01?terminate@@YAXXZ"] - unwind to caller +The ``catchpad`` and ``cleanuppad`` instructions establish new funclets, and +their tokens are consumed by other "pad" instructions to establish membership. +The ``catchswitch`` instruction does not create a funclet, but it produces a +token that is always consumed by its immediate successor ``catchpad`` +instructions. This ensures that every catch handler modelled by a ``catchpad`` +belongs to exactly one ``catchswitch``, which models the dispatch point after a +C++ try. The ``terminatepad`` instruction cannot contain lexically nested +funclets inside the termination action, so it does not produce a token. + +Here is an example of what this nesting looks like using some hypothetical +C++ code: + +.. code-block:: c + + void f() { + try { + throw; + } catch (...) { + try { + throw; + } catch (...) { + } + } } + +.. code-block:: llvm + define void @f() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { + entry: + invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #1 + to label %unreachable unwind label %catch.dispatch + + catch.dispatch: ; preds = %entry + %0 = catchswitch within none [label %catch] unwind to caller + + catch: ; preds = %catch.dispatch + %1 = catchpad within %0 [i8* null, i32 64, i8* null] + invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #1 + to label %unreachable unwind label %catch.dispatch2 + + catch.dispatch2: ; preds = %catch + %2 = catchswitch within %1 [label %catch3] unwind to caller + + catch3: ; preds = %catch.dispatch2 + %3 = catchpad within %2 [i8* null, i32 64, i8* null] + catchret from %3 to label %try.cont + + try.cont: ; preds = %catch3 + catchret from %1 to label %try.cont6 + + try.cont6: ; preds = %try.cont + ret void + + unreachable: ; preds = %catch, %entry + unreachable + } + +The "inner" ``catchswitch`` consumes ``%1`` which is produced by the outer +catchswitch. Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -5001,10 +5001,8 @@ The terminator instructions are: ':ref:`ret `', ':ref:`br `', ':ref:`switch `', ':ref:`indirectbr `', ':ref:`invoke `', -':ref:`resume `', ':ref:`catchpad `', -':ref:`catchendpad `', +':ref:`resume `', ':ref:`catchswitch `', ':ref:`catchret `', -':ref:`cleanupendpad `', ':ref:`cleanupret `', ':ref:`terminatepad `', and ':ref:`unreachable `'. @@ -5362,9 +5360,9 @@ resume { i8*, i32 } %exn -.. _i_catchpad: +.. _i_catchswitch: -'``catchpad``' Instruction +'``catchswitch``' Instruction ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Syntax: @@ -5372,155 +5370,125 @@ :: - = catchpad [*] - to label unwind label + = catchswitch within [ label , label , ... ] unwind to caller + = catchswitch within [ label , label , ... ] unwind label Overview: """"""""" -The '``catchpad``' instruction is used by `LLVM's exception handling -system `_ to specify that a basic block -is a catch block --- one where a personality routine attempts to transfer -control to catch an exception. -The ``args`` correspond to whatever information the personality -routine requires to know if this is an appropriate place to catch the -exception. Control is transfered to the ``exception`` label if the -``catchpad`` is not an appropriate handler for the in-flight exception. -The ``normal`` label should contain the code found in the ``catch`` -portion of a ``try``/``catch`` sequence. The ``resultval`` has the type -:ref:`token ` and is used to match the ``catchpad`` to -corresponding :ref:`catchrets `. +The '``catchswitch``' instruction is used by `LLVM's exception handling system +`_ to describe the set of possible catch handlers +that may be executed by the :ref:`EH personality routine `. Arguments: """""""""" -The instruction takes a list of arbitrary values which are interpreted -by the :ref:`personality function `. +The ``parent`` argument is the token of the funclet that contains the +``catchswitch`` instruction. If the ``catchswitch`` is not inside a funclet, +this operand may be the token ``none``. -The ``catchpad`` must be provided a ``normal`` label to transfer control -to if the ``catchpad`` matches the exception and an ``exception`` -label to transfer control to if it doesn't. +The ``default`` argument is the label of another basic block beginning with a +"pad" instruction, one of ``cleanuppad``, ``terminatepad``, or +``catchswitch``. + +The ``handlers`` are a list of successor blocks that each begin with a +:ref:`catchpad ` instruction. Semantics: """""""""" -When the call stack is being unwound due to an exception being thrown, -the exception is compared against the ``args``. If it doesn't match, -then control is transfered to the ``exception`` basic block. -As with calling conventions, how the personality function results are -represented in LLVM IR is target specific. +Executing this instruction transfers control to one of the successors in +``handlers``, if appropriate, or continues to unwind via the unwind label if +present. -The ``catchpad`` instruction has several restrictions: - -- A catch block is a basic block which is the unwind destination of - an exceptional instruction. -- A catch block must have a '``catchpad``' instruction as its - first non-PHI instruction. -- A catch block's ``exception`` edge must refer to a catch block or a - catch-end block. -- There can be only one '``catchpad``' instruction within the - catch block. -- A basic block that is not a catch block may not include a - '``catchpad``' instruction. -- A catch block which has another catch block as a predecessor may not have - any other predecessors. -- It is undefined behavior for control to transfer from a ``catchpad`` to a - ``ret`` without first executing a ``catchret`` that consumes the - ``catchpad`` or unwinding through its ``catchendpad``. -- It is undefined behavior for control to transfer from a ``catchpad`` to - itself without first executing a ``catchret`` that consumes the - ``catchpad`` or unwinding through its ``catchendpad``. +The ``catchswitch`` is both a terminator and a "pad" instruction, meaning that +it must be both the first non-phi instruction and last instruction in the basic +block. Therefore, it must be the only non-phi instruction in the block. Example: """""""" .. code-block:: llvm - ;; A catch block which can catch an integer. - %tok = catchpad [i8** @_ZTIi] - to label %int.handler unwind label %terminate + dispatch1: + %cs1 = catchswitch within none [label %handler0, label %handler1] unwind to caller + dispatch2: + %cs2 = catchswitch within %parenthandler [label %handler0] unwind label %cleanup -.. _i_catchendpad: +.. _i_catchpad: -'``catchendpad``' Instruction -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +'``catchpad``' Instruction +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Syntax: """"""" :: - catchendpad unwind label - catchendpad unwind to caller + = catchpad within [*] Overview: """"""""" -The '``catchendpad``' instruction is used by `LLVM's exception handling -system `_ to communicate to the -:ref:`personality function ` which invokes are associated -with a chain of :ref:`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 ` will continue processing -exception handling actions in the caller. +The '``catchpad``' instruction is used by `LLVM's exception handling +system `_ to specify that a basic block +begins a catch handler --- one where a personality routine attempts to transfer +control to catch an exception. Arguments: """""""""" -The instruction optionally takes a label, ``nextaction``, indicating -where control should transfer to if none of the preceding -``catchpad`` instructions are suitable for the in-flight exception. +The ``catchswitch`` operand must always be a token produced by a +:ref:`catchswitch ` instruction in a predecessor block. This +ensures that each ``catchpad`` has exactly one predecessor block, and it always +terminates in a ``catchswitch``. + +The ``args`` correspond to whatever information the personality routine +requires to know if this is an appropriate handler for the exception. Control +will transfer to the ``catchpad`` if this is the first appropriate handler for +the exception. + +The ``resultval`` has the type :ref:`token ` and is used to match the +``catchpad`` to corresponding :ref:`catchrets ` and other nested EH +pads. Semantics: """""""""" -When the call stack is being unwound due to an exception being thrown -and none of the constituent ``catchpad`` instructions match, then -control is transfered to ``nextaction`` if it is present. If it is not -present, control is transfered to the caller. +When the call stack is being unwound due to an exception being thrown, the +exception is compared against the ``args``. If it doesn't match, control will +not reach the ``catchpad`` instruction. The representation of ``args`` is +entirely target and personality function-specific. -The ``catchendpad`` instruction has several restrictions: +Like the :ref:`landingpad ` instruction, the ``catchpad`` +instruction must be the first non-phi of its parent basic block. -- A catch-end block is a basic block which is the unwind destination of - an exceptional instruction. -- A catch-end block must have a '``catchendpad``' instruction as its - first non-PHI instruction. -- There can be only one '``catchendpad``' instruction within the - catch-end block. -- A basic block that is not a catch-end block may not include a - '``catchendpad``' instruction. -- Exactly one catch block may unwind to a ``catchendpad``. -- It is undefined behavior to execute a ``catchendpad`` if none of the - '``catchpad``'s chained to it have been executed. -- It is undefined behavior to execute a ``catchendpad`` twice without an - intervening execution of one or more of the '``catchpad``'s chained to it. -- It is undefined behavior to execute a ``catchendpad`` if, after the most - recent execution of the normal successor edge of any ``catchpad`` chained - to it, some ``catchret`` consuming that ``catchpad`` has already been - executed. -- It is undefined behavior to execute a ``catchendpad`` if, after the most - recent execution of the normal successor edge of any ``catchpad`` chained - to it, any other ``catchpad`` or ``cleanuppad`` has been executed but has - not had a corresponding - ``catchret``/``cleanupret``/``catchendpad``/``cleanupendpad`` executed. +The meaning of the tokens produced and consumed by ``catchpad`` and other "pad" +instructions is described in the +`Windows exception handling documentation `. + +Executing a ``catchpad`` instruction constitutes "entering" that pad. +The pad may then be "exited" in one of three ways: +1) explicitly via a ``catchret`` that consumes it. Executing such a ``catchret`` + is undefined behavior if any descendant pads have been entered but not yet + exited. +2) implicitly via a call (which unwinds all the way to the current function's caller), + or via a ``catchswitch``, ``cleanupret``, or ``terminatepad`` that unwinds to caller. +3) implicitly via an unwind edge whose destination EH pad isn't a descendant of + the ``catchpad``. When the ``catchpad`` is exited in this manner, it is + undefined behavior if the destination EH pad has a parent which is not an + ancestor of the ``catchpad`` being exited. Example: """""""" .. code-block:: llvm - catchendpad unwind label %terminate - catchendpad unwind to caller + dispatch: + %cs = catchswitch within none [label %handler0] unwind to caller + ;; A catch block which can catch an integer. + handler0: + %tok = catchpad within %cs [i8** @_ZTIi] .. _i_catchret: @@ -5532,7 +5500,7 @@ :: - catchret to label + catchret from to label Overview: """"""""" @@ -5552,105 +5520,24 @@ Semantics: """""""""" -The '``catchret``' instruction ends the existing (in-flight) exception -whose unwinding was interrupted with a -:ref:`catchpad ` instruction. -The :ref:`personality function ` gets a chance to execute -arbitrary code to, for example, run a C++ destructor. -Control then transfers to ``normal``. -It may be passed an optional, personality specific, value. - -It is undefined behavior to execute a ``catchret`` whose ``catchpad`` has -not been executed. - -It is undefined behavior to execute a ``catchret`` if, after the most recent -execution of its ``catchpad``, some ``catchret`` or ``catchendpad`` linked -to the same ``catchpad`` has already been executed. - -It is undefined behavior to execute a ``catchret`` if, after the most recent -execution of its ``catchpad``, any other ``catchpad`` or ``cleanuppad`` has -been executed but has not had a corresponding -``catchret``/``cleanupret``/``catchendpad``/``cleanupendpad`` executed. - -Example: -"""""""" - -.. code-block:: llvm - - catchret %catch label %continue - -.. _i_cleanupendpad: - -'``cleanupendpad``' Instruction -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Syntax: -""""""" - -:: - - cleanupendpad unwind label - cleanupendpad unwind to caller - -Overview: -""""""""" - -The '``cleanupendpad``' instruction is used by `LLVM's exception handling -system `_ to communicate to the -:ref:`personality function ` which invokes are associated -with a :ref:`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 ` 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 `. -It also has an optional successor, ``nextaction``, indicating where control -should transfer to. - -Semantics: -"""""""""" - -When and exception propagates to a ``cleanupendpad``, control is transfered to -``nextaction`` if it is present. If it is not present, control is transfered to -the caller. +The '``catchret``' instruction ends an existing (in-flight) exception whose +unwinding was interrupted with a :ref:`catchpad ` instruction. The +:ref:`personality function ` gets a chance to execute arbitrary +code to, for example, destroy the active exception. Control then transfers to +``normal``. -The ``cleanupendpad`` instruction has several restrictions: - -- A cleanup-end block is a basic block which is the unwind destination of - an exceptional instruction. -- A cleanup-end block must have a '``cleanupendpad``' instruction as its - first non-PHI instruction. -- There can be only one '``cleanupendpad``' instruction within the - cleanup-end block. -- A basic block that is not a cleanup-end block may not include a - '``cleanupendpad``' instruction. -- It is undefined behavior to execute a ``cleanupendpad`` whose ``cleanuppad`` - has not been executed. -- It is undefined behavior to execute a ``cleanupendpad`` if, after the most - recent execution of its ``cleanuppad``, some ``cleanupret`` or ``cleanupendpad`` - consuming the same ``cleanuppad`` has already been executed. -- It is undefined behavior to execute a ``cleanupendpad`` if, after the most - recent execution of its ``cleanuppad``, any other ``cleanuppad`` or - ``catchpad`` has been executed but has not had a corresponding - ``cleanupret``/``catchret``/``cleanupendpad``/``catchendpad`` executed. +The ``token`` argument must be a token produced by a dominating ``catchpad`` +instruction. The ``catchret`` destroys the physical frame established by +``catchpad``, so executing multiple returns on the same token without +re-executing the ``catchpad`` will result in undefined behavior. +See :ref:`catchpad ` for more details. Example: """""""" .. code-block:: llvm - cleanupendpad %cleanup unwind label %terminate - cleanupendpad %cleanup unwind to caller + catchret from %catch label %continue .. _i_cleanupret: @@ -5662,8 +5549,8 @@ :: - cleanupret unwind label - cleanupret unwind to caller + cleanupret from unwind label + cleanupret from unwind to caller Overview: """"""""" @@ -5687,25 +5574,20 @@ :ref:`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 ` 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 @@ :: - terminatepad [*] unwind label - terminatepad [*] unwind to caller + terminatepad within [*] unwind label + terminatepad within [*] unwind to caller Overview: """"""""" @@ -5752,16 +5634,8 @@ 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 @@ .. 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 @@ :: - = cleanuppad [*] + = cleanuppad within [*] Overview: """"""""" @@ -8775,8 +8649,10 @@ information the :ref:`personality function ` requires to execute the cleanup. The ``resultval`` has the type :ref:`token ` and is used to -match the ``cleanuppad`` to corresponding :ref:`cleanuprets ` -and :ref:`cleanupendpads `. +match the ``cleanuppad`` to corresponding :ref:`cleanuprets `. +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 @@ 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: Index: include/llvm-c/Core.h =================================================================== --- include/llvm-c/Core.h +++ include/llvm-c/Core.h @@ -254,8 +254,7 @@ LLVMCatchPad = 63, LLVMTerminatePad = 64, LLVMCleanupPad = 65, - LLVMCatchEndPad = 66, - LLVMCleanupEndPad = 67 + LLVMCatchSwitch = 66 } LLVMOpcode; typedef enum { @@ -1211,7 +1210,6 @@ macro(InsertElementInst) \ macro(InsertValueInst) \ macro(LandingPadInst) \ - macro(CleanupPadInst) \ macro(PHINode) \ macro(SelectInst) \ macro(ShuffleVectorInst) \ @@ -1226,10 +1224,10 @@ 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) \ Index: include/llvm/Analysis/EHPersonalities.h =================================================================== --- include/llvm/Analysis/EHPersonalities.h +++ include/llvm/Analysis/EHPersonalities.h @@ -10,9 +10,12 @@ #ifndef LLVM_ANALYSIS_EHPERSONALITIES_H #define LLVM_ANALYSIS_EHPERSONALITIES_H +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/TinyPtrVector.h" #include "llvm/Support/ErrorHandling.h" namespace llvm { +class BasicBlock; class Function; class Value; @@ -78,6 +81,14 @@ bool canSimplifyInvokeNoUnwind(const Function *F); +typedef TinyPtrVector 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 colorEHFunclets(Function &F); + } // end namespace llvm #endif Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -423,9 +423,8 @@ 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...] }; Index: include/llvm/CodeGen/WinEHFuncInfo.h =================================================================== --- include/llvm/CodeGen/WinEHFuncInfo.h +++ include/llvm/CodeGen/WinEHFuncInfo.h @@ -89,9 +89,11 @@ struct WinEHFuncInfo { DenseMap EHPadStateMap; + DenseMap FuncletBaseStateMap; + DenseMap InvokeStateMap; DenseMap CatchRetSuccessorColorMap; - DenseMap> InvokeToStateMap; + DenseMap> LabelToStateMap; SmallVector CxxUnwindMap; SmallVector TryBlockMap; SmallVector SEHUnwindMap; @@ -101,7 +103,7 @@ 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; Index: include/llvm/IR/IRBuilder.h =================================================================== --- include/llvm/IR/IRBuilder.h +++ include/llvm/IR/IRBuilder.h @@ -708,29 +708,30 @@ return Insert(CleanupReturnInst::Create(CleanupPad, UnwindBB)); } - CleanupEndPadInst *CreateCleanupEndPad(CleanupPadInst *CleanupPad, - BasicBlock *UnwindBB = nullptr) { - return Insert(CleanupEndPadInst::Create(CleanupPad, UnwindBB)); - } - - CatchPadInst *CreateCatchPad(BasicBlock *NormalDest, BasicBlock *UnwindDest, - ArrayRef Args, const Twine &Name = "") { - return Insert(CatchPadInst::Create(NormalDest, UnwindDest, Args), Name); + CatchSwitchInst *CreateCatchSwitch(Value *OuterScope, + BasicBlock *UnwindBB, + unsigned NumHandlers, + const Twine &Name = "") { + return Insert(CatchSwitchInst::Create(OuterScope, UnwindBB, NumHandlers), + Name); } - CatchEndPadInst *CreateCatchEndPad(BasicBlock *UnwindBB = nullptr) { - return Insert(CatchEndPadInst::Create(Context, UnwindBB)); + CatchPadInst *CreateCatchPad(Value *OuterScope, ArrayRef Args, + const Twine &Name = "") { + return Insert(CatchPadInst::Create(OuterScope, Args), Name); } - TerminatePadInst *CreateTerminatePad(BasicBlock *UnwindBB = nullptr, - ArrayRef Args = {}, + TerminatePadInst *CreateTerminatePad(Value *OuterScope, + BasicBlock *UnwindBB = nullptr, + ArrayRef Args = None, const Twine &Name = "") { - return Insert(TerminatePadInst::Create(Context, UnwindBB, Args), Name); + return Insert(TerminatePadInst::Create(OuterScope, UnwindBB, Args), Name); } - CleanupPadInst *CreateCleanupPad(ArrayRef Args, + CleanupPadInst *CreateCleanupPad(Value *OuterScope, + ArrayRef Args = None, const Twine &Name = "") { - return Insert(CleanupPadInst::Create(Context, Args), Name); + return Insert(CleanupPadInst::Create(OuterScope, Args), Name); } CatchReturnInst *CreateCatchRet(CatchPadInst *CatchPad, BasicBlock *BB) { Index: include/llvm/IR/InstVisitor.h =================================================================== --- include/llvm/IR/InstVisitor.h +++ include/llvm/IR/InstVisitor.h @@ -170,10 +170,8 @@ 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 @@ 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);} Index: include/llvm/IR/InstrTypes.h =================================================================== --- include/llvm/IR/InstrTypes.h +++ include/llvm/IR/InstrTypes.h @@ -82,10 +82,8 @@ // \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 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CmpInst, Value) +//===----------------------------------------------------------------------===// +// FuncletPadInst Class +//===----------------------------------------------------------------------===// +class FuncletPadInst : public Instruction { +private: + void init(Value *OuterScope, ArrayRef Args, const Twine &NameStr); + + FuncletPadInst(const FuncletPadInst &CPI); + + explicit FuncletPadInst(Instruction::FuncletPadOps Op, Value *OuterScope, + ArrayRef Args, unsigned Values, + const Twine &NameStr, Instruction *InsertBefore); + explicit FuncletPadInst(Instruction::FuncletPadOps Op, Value *OuterScope, + ArrayRef 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 *OuterScope) { + assert(OuterScope); + Op<-1>() = OuterScope; + } + + /// 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(V) && classof(cast(V)); + } +}; + +template <> +struct OperandTraits + : public VariadicOperandTraits {}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(FuncletPadInst, Value) + /// \brief A lightweight accessor for an operand bundle meant to be passed /// around by value. struct OperandBundleUse { Index: include/llvm/IR/Instruction.h =================================================================== --- include/llvm/IR/Instruction.h +++ include/llvm/IR/Instruction.h @@ -109,6 +109,7 @@ 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 @@ 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 @@ /// \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 @@ #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, Index: include/llvm/IR/Instruction.def =================================================================== --- include/llvm/IR/Instruction.def +++ include/llvm/IR/Instruction.def @@ -74,6 +74,20 @@ #define LAST_CAST_INST(num) #endif +#ifndef FIRST_FUNCLETPAD_INST +#define FIRST_FUNCLETPAD_INST(num) +#endif +#ifndef HANDLE_FUNCLETPAD_INST +#ifndef HANDLE_INST +#define HANDLE_FUNCLETPAD_INST(num, opcode, Class) +#else +#define HANDLE_FUNCLETPAD_INST(num, opcode, Class) HANDLE_INST(num, opcode, Class) +#endif +#endif +#ifndef LAST_FUNCLETPAD_INST +#define LAST_FUNCLETPAD_INST(num) +#endif + #ifndef FIRST_OTHER_INST #define FIRST_OTHER_INST(num) #endif @@ -102,65 +116,68 @@ HANDLE_TERM_INST ( 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(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 @@ #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 Index: include/llvm/IR/Instructions.h =================================================================== --- include/llvm/IR/Instructions.h +++ include/llvm/IR/Instructions.h @@ -18,6 +18,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/iterator_range.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/CallingConv.h" @@ -3819,181 +3820,176 @@ 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 *OuterScope, 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 *OuterScope, 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 *OuterScope, 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 *OuterScope, 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(OuterScope, UnwindDest, NumHandlers, NameStr, + InsertBefore); } - static CatchEndPadInst *Create(LLVMContext &C, BasicBlock *UnwindBB, + static CatchSwitchInst *Create(Value *OuterScope, 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(OuterScope, 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 *OuterScope) { setOperand(0, OuterScope); } + + // 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(Op<-1>()) : nullptr; + if (hasUnwindDest()) + return cast(getOperand(1)); + return nullptr; } - void setUnwindDest(BasicBlock *NewDest) { - assert(NewDest); - Op<-1>() = NewDest; + void setUnwindDest(BasicBlock *UnwindDest) { + assert(UnwindDest); + assert(hasUnwindDest()); + setOperand(1, UnwindDest); } - // Methods for support type inquiry through isa, cast, and dyn_cast: - static inline bool classof(const Instruction *I) { - return (I->getOpcode() == Instruction::CatchEndPad); - } - static inline bool classof(const Value *V) { - return isa(V) && classof(cast(V)); + /// getNumHandlers - return the number of 'handlers' in this catchswitch + /// instruction, except the default handler + unsigned getNumHandlers() const { + if (hasUnwindDest()) + return getNumOperands() - 2; + return getNumOperands() - 1; } private: - BasicBlock *getSuccessorV(unsigned Idx) const override; - unsigned getNumSuccessorsV() const override; - void setSuccessorV(unsigned Idx, BasicBlock *B) override; - - // Shadow Instruction::setInstructionSubclassData with a private forwarding - // method so that subclasses cannot accidentally use it. - void setInstructionSubclassData(unsigned short D) { - Instruction::setInstructionSubclassData(D); + static BasicBlock *handler_helper(Value *V) { return cast(V); } + static const BasicBlock *handler_helper(const Value *V) { + return cast(V); } -}; - -template <> -struct OperandTraits - : public VariadicOperandTraits {}; - -DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CatchEndPadInst, Value) - -//===----------------------------------------------------------------------===// -// CatchPadInst Class -//===----------------------------------------------------------------------===// - -class CatchPadInst : public TerminatorInst { -private: - void init(BasicBlock *IfNormal, BasicBlock *IfException, - ArrayRef Args, const Twine &NameStr); - - CatchPadInst(const CatchPadInst &CPI); - - explicit CatchPadInst(BasicBlock *IfNormal, BasicBlock *IfException, - ArrayRef Args, unsigned Values, - const Twine &NameStr, Instruction *InsertBefore); - explicit CatchPadInst(BasicBlock *IfNormal, BasicBlock *IfException, - ArrayRef 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 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 Args, const Twine &NameStr, - BasicBlock *InsertAtEnd) { - unsigned Values = unsigned(Args.size()) + 2; - return new (Values) - CatchPadInst(IfNormal, IfException, Args, Values, NameStr, InsertAtEnd); - } + typedef std::pointer_to_unary_function DerefFnTy; + typedef mapped_iterator handler_iterator; + typedef iterator_range handler_range; - /// Provide fast operand accessors - DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); - /// getNumArgOperands - Return the number of catchpad arguments. - /// - unsigned getNumArgOperands() const { return getNumOperands() - 2; } + typedef std::pointer_to_unary_function + ConstDerefFnTy; + typedef mapped_iterator const_handler_iterator; + typedef iterator_range const_handler_range; - /// getArgOperand/setArgOperand - Return/set the i-th catchpad argument. - /// - Value *getArgOperand(unsigned i) const { return getOperand(i); } - void setArgOperand(unsigned i, Value *v) { setOperand(i, v); } + /// Returns an iterator that points to the first handler in CatchSwitchInst. + handler_iterator handler_begin() { + op_iterator It = op_begin() + 1; + if (hasUnwindDest()) + ++It; + return handler_iterator(It, DerefFnTy(handler_helper)); + } + /// Returns an iterator that points to the first handler in the + /// CatchSwitchInst. + const_handler_iterator handler_begin() const { + const_op_iterator It = op_begin() + 1; + if (hasUnwindDest()) + ++It; + return const_handler_iterator(It, ConstDerefFnTy(handler_helper)); + } - /// arg_operands - iteration adapter for range-for loops. - iterator_range arg_operands() { - return make_range(op_begin(), op_end() - 2); + /// Returns a read-only iterator that points one past the last + /// handler in the CatchSwitchInst. + handler_iterator handler_end() { + return handler_iterator(op_end(), DerefFnTy(handler_helper)); + } + /// Returns an iterator that points one past the last handler in the + /// CatchSwitchInst. + const_handler_iterator handler_end() const { + return const_handler_iterator(op_end(), ConstDerefFnTy(handler_helper)); } - /// arg_operands - iteration adapter for range-for loops. - iterator_range arg_operands() const { - return make_range(op_begin(), op_end() - 2); + /// handlers - iteration adapter for range-for loops. + handler_range handlers() { + return make_range(handler_begin(), handler_end()); } - /// \brief Wrappers for getting the \c Use of a catchpad argument. - const Use &getArgOperandUse(unsigned i) const { return getOperandUse(i); } - Use &getArgOperandUse(unsigned i) { return getOperandUse(i); } + /// handlers - iteration adapter for range-for loops. + const_handler_range handlers() const { + return make_range(handler_begin(), handler_end()); + } - // get*Dest - Return the destination basic blocks... - BasicBlock *getNormalDest() const { return cast(Op<-2>()); } - BasicBlock *getUnwindDest() const { return cast(Op<-1>()); } - void setNormalDest(BasicBlock *B) { Op<-2>() = B; } - void setUnwindDest(BasicBlock *B) { Op<-1>() = B; } + /// addHandler - Add an entry to the switch instruction... + /// Note: + /// This action invalidates handler_end(). Old handler_end() iterator will + /// point to the added handler. + void addHandler(BasicBlock *Dest); - BasicBlock *getSuccessor(unsigned i) const { - assert(i < 2 && "Successor # out of range for catchpad!"); - return i == 0 ? getNormalDest() : getUnwindDest(); + unsigned getNumSuccessors() const { return getNumOperands() - 1; } + BasicBlock *getSuccessor(unsigned Idx) const { + assert(Idx < getNumSuccessors() && + "Successor # out of range for catchswitch!"); + return cast(getOperand(Idx + 1)); } - - void setSuccessor(unsigned idx, BasicBlock *NewSucc) { - assert(idx < 2 && "Successor # out of range for catchpad!"); - *(&Op<-2>() + idx) = NewSucc; + void setSuccessor(unsigned Idx, BasicBlock *NewSucc) { + assert(Idx < getNumSuccessors() && + "Successor # out of range for catchswitch!"); + setOperand(Idx + 1, NewSucc); } - unsigned getNumSuccessors() const { return 2; } - // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { - return I->getOpcode() == Instruction::CatchPad; + return I->getOpcode() == Instruction::CatchSwitch; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } private: - BasicBlock *getSuccessorV(unsigned idx) const override; + BasicBlock *getSuccessorV(unsigned Idx) const override; unsigned getNumSuccessorsV() const override; - void setSuccessorV(unsigned idx, BasicBlock *B) override; + void setSuccessorV(unsigned Idx, BasicBlock *B) override; }; template <> -struct OperandTraits - : public VariadicOperandTraits {}; +struct OperandTraits : public HungoffOperandTraits<2> {}; -DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CatchPadInst, Value) +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CatchSwitchInst, Value) //===----------------------------------------------------------------------===// // TerminatePadInst Class @@ -4001,14 +3997,14 @@ class TerminatePadInst : public TerminatorInst { private: - void init(BasicBlock *BB, ArrayRef Args); + void init(Value *OuterScope, BasicBlock *BB, ArrayRef Args); TerminatePadInst(const TerminatePadInst &TPI); - explicit TerminatePadInst(LLVMContext &C, BasicBlock *BB, + explicit TerminatePadInst(Value *OuterScope, BasicBlock *BB, ArrayRef Args, unsigned Values, Instruction *InsertBefore); - explicit TerminatePadInst(LLVMContext &C, BasicBlock *BB, + explicit TerminatePadInst(Value *OuterScope, BasicBlock *BB, ArrayRef Args, unsigned Values, BasicBlock *InsertAtEnd); @@ -4018,21 +4014,23 @@ TerminatePadInst *cloneImpl() const; public: - static TerminatePadInst *Create(LLVMContext &C, BasicBlock *BB = nullptr, + static TerminatePadInst *Create(Value *OuterScope, BasicBlock *BB = nullptr, ArrayRef 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(OuterScope, BB, Args, Values, InsertBefore); } - static TerminatePadInst *Create(LLVMContext &C, BasicBlock *BB, + static TerminatePadInst *Create(Value *OuterScope, BasicBlock *BB, ArrayRef 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(OuterScope, BB, Args, Values, InsertAtEnd); } /// Provide fast operand accessors @@ -4046,8 +4044,15 @@ 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 *OuterScope) { + assert(OuterScope); + Op<-1>() = OuterScope; } /// getArgOperand/setArgOperand - Return/set the i-th terminatepad argument. @@ -4055,26 +4060,29 @@ 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 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 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 @@ BasicBlock *getUnwindDest() const { if (!hasUnwindDest()) return nullptr; - return cast(Op<-1>()); + return cast(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,38 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(TerminatePadInst, Value) //===----------------------------------------------------------------------===// -// CleanupPadInst Class +// CleanupPadInst Class //===----------------------------------------------------------------------===// - -class CleanupPadInst : public Instruction { +class CleanupPadInst : public FuncletPadInst { private: - void init(ArrayRef Args, const Twine &NameStr); - - CleanupPadInst(const CleanupPadInst &CPI); - - explicit CleanupPadInst(LLVMContext &C, ArrayRef Args, - const Twine &NameStr, Instruction *InsertBefore); - explicit CleanupPadInst(LLVMContext &C, ArrayRef 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 *OuterScope, ArrayRef Args, + unsigned Values, const Twine &NameStr, + Instruction *InsertBefore) + : FuncletPadInst(Instruction::CleanupPad, OuterScope, Args, Values, + NameStr, InsertBefore) {} + explicit CleanupPadInst(Value *OuterScope, ArrayRef Args, + unsigned Values, const Twine &NameStr, + BasicBlock *InsertAtEnd) + : FuncletPadInst(Instruction::CleanupPad, OuterScope, Args, Values, + NameStr, InsertAtEnd) {} public: - static CleanupPadInst *Create(LLVMContext &C, ArrayRef Args, + static CleanupPadInst *Create(Value *OuterScope, + ArrayRef 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(OuterScope, Args, Values, NameStr, InsertBefore); } - static CleanupPadInst *Create(LLVMContext &C, ArrayRef Args, + static CleanupPadInst *Create(Value *OuterScope, ArrayRef Args, const Twine &NameStr, BasicBlock *InsertAtEnd) { - return new (Args.size()) CleanupPadInst(C, Args, NameStr, InsertAtEnd); + unsigned Values = 1 + Args.size(); + return new (Values) + CleanupPadInst(OuterScope, 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 +4169,54 @@ } }; -template <> -struct OperandTraits - : public VariadicOperandTraits {}; +//===----------------------------------------------------------------------===// +// CatchPadInst Class +//===----------------------------------------------------------------------===// +class CatchPadInst : public FuncletPadInst { +private: + explicit CatchPadInst(Value *CatchSwitch, ArrayRef Args, + unsigned Values, const Twine &NameStr, + Instruction *InsertBefore) + : FuncletPadInst(Instruction::CatchPad, CatchSwitch, Args, Values, + NameStr, InsertBefore) {} + explicit CatchPadInst(Value *CatchSwitch, ArrayRef 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 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 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(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(V) && classof(cast(V)); + } +}; //===----------------------------------------------------------------------===// // CatchReturnInst Class @@ -4176,11 +4225,9 @@ 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 +4235,13 @@ 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 +4265,10 @@ } unsigned getNumSuccessors() const { return 1; } + Value *getParentPad() const { + return getCatchPad()->getCatchSwitch()->getParentPad(); + } + // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return (I->getOpcode() == Instruction::CatchRet); @@ -4239,93 +4290,6 @@ 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(Op<-1>()); - } - void setCleanupPad(CleanupPadInst *CleanupPad) { - assert(CleanupPad); - Op<-1>() = CleanupPad; - } - - BasicBlock *getUnwindDest() const { - return hasUnwindDest() ? cast(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(V) && classof(cast(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 - : public VariadicOperandTraits {}; - -DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CleanupEndPadInst, Value) - -//===----------------------------------------------------------------------===// // CleanupReturnInst Class //===----------------------------------------------------------------------===// @@ -4333,11 +4297,11 @@ 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 +4309,7 @@ CleanupReturnInst *cloneImpl() const; public: - static CleanupReturnInst *Create(CleanupPadInst *CleanupPad, + static CleanupReturnInst *Create(Value *CleanupPad, BasicBlock *UnwindBB = nullptr, Instruction *InsertBefore = nullptr) { assert(CleanupPad); @@ -4355,8 +4319,7 @@ 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 +4337,22 @@ /// Convenience accessor. CleanupPadInst *getCleanupPad() const { - return cast(Op<-1>()); + return cast(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(Op<-2>()) : nullptr; + return hasUnwindDest() ? cast(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: Index: include/llvm/Transforms/Utils/Local.h =================================================================== --- include/llvm/Transforms/Utils/Local.h +++ include/llvm/Transforms/Utils/Local.h @@ -289,8 +289,8 @@ 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. Index: lib/Analysis/CaptureTracking.cpp =================================================================== --- lib/Analysis/CaptureTracking.cpp +++ lib/Analysis/CaptureTracking.cpp @@ -80,12 +80,11 @@ 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(BeforeHere) || isa(BeforeHere) || - isa(I) || I == BeforeHere) + if (isa(BeforeHere) || isa(I) || I == BeforeHere) return false; if (!OrderedBB->dominates(BeforeHere, I)) return false; Index: lib/Analysis/EHPersonalities.cpp =================================================================== --- lib/Analysis/EHPersonalities.cpp +++ lib/Analysis/EHPersonalities.cpp @@ -9,7 +9,11 @@ #include "llvm/Analysis/EHPersonalities.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/IR/CFG.h" +#include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/Support/Debug.h" using namespace llvm; /// See if the given exception handling personality function is one that we @@ -39,3 +43,64 @@ // implies that the function does not throw synchronous exceptions. return !isAsynchronousEHPersonality(Personality); } + +DenseMap llvm::colorEHFunclets(Function &F) { + SmallVector, 16> Worklist; + BasicBlock *EntryBlock = &F.getEntryBlock(); + DenseMap 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(Terminator)) { + Value *OuterScope = CatchRet->getParentPad(); + if (isa(OuterScope)) + SuccColor = EntryBlock; + else + SuccColor = cast(OuterScope)->getParent(); + } + + for (BasicBlock *Succ : successors(Visiting)) + Worklist.push_back({Succ, SuccColor}); + } + return BlockColors; +} Index: lib/Analysis/InstructionSimplify.cpp =================================================================== --- lib/Analysis/InstructionSimplify.cpp +++ lib/Analysis/InstructionSimplify.cpp @@ -122,10 +122,10 @@ 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(I) && !isa(I)) + !isa(I)) return true; return false; Index: lib/Analysis/LoopInfo.cpp =================================================================== --- lib/Analysis/LoopInfo.cpp +++ lib/Analysis/LoopInfo.cpp @@ -227,9 +227,15 @@ if (isa((*I)->getTerminator())) return false; - if (const InvokeInst *II = dyn_cast((*I)->getTerminator())) + if (const InvokeInst *II = dyn_cast((*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(FirstNonPHI)) + return false; + } for (BasicBlock::iterator BI = (*I)->begin(), BE = (*I)->end(); BI != BE; ++BI) { if (const CallInst *CI = dyn_cast(BI)) { Index: lib/Analysis/ScalarEvolutionExpander.cpp =================================================================== --- lib/Analysis/ScalarEvolutionExpander.cpp +++ lib/Analysis/ScalarEvolutionExpander.cpp @@ -91,22 +91,16 @@ BasicBlock::iterator IP = ++I->getIterator(); if (auto *II = dyn_cast(I)) IP = II->getNormalDest()->begin(); - if (auto *CPI = dyn_cast(I)) - IP = CPI->getNormalDest()->begin(); while (isa(IP)) ++IP; while (IP->isEHPad()) { - if (isa(IP) || isa(IP)) { + if (isa(IP) || isa(IP)) { ++IP; } else if (auto *TPI = dyn_cast(IP)) { IP = TPI->getUnwindDest()->getFirstNonPHI()->getIterator(); - } else if (auto *CEPI = dyn_cast(IP)) { - IP = CEPI->getUnwindDest()->getFirstNonPHI()->getIterator(); - } else if (auto *CEPI = dyn_cast(IP)) { - IP = CEPI->getUnwindDest()->getFirstNonPHI()->getIterator(); - } else if (isa(IP)) { + } else if (isa(IP)) { IP = MustDominate->getFirstInsertionPt(); } else { llvm_unreachable("unexpected eh pad!"); Index: lib/Analysis/ValueTracking.cpp =================================================================== --- lib/Analysis/ValueTracking.cpp +++ lib/Analysis/ValueTracking.cpp @@ -3431,11 +3431,10 @@ 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 Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -526,6 +526,8 @@ KEYWORD(none); KEYWORD(to); KEYWORD(caller); + KEYWORD(within); + KEYWORD(from); KEYWORD(tail); KEYWORD(musttail); KEYWORD(notail); @@ -759,11 +761,10 @@ 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) \ Index: lib/AsmParser/LLParser.h =================================================================== --- lib/AsmParser/LLParser.h +++ lib/AsmParser/LLParser.h @@ -108,14 +108,6 @@ 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 InstsWithTBAATag; // Type resolution handling data structures. The location is set when we @@ -337,10 +329,8 @@ /// 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 @@ }; 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 @@ 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); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -2315,7 +2315,7 @@ /// 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 @@ // 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(Val)) { - P.Error(Loc, "'%" + Name + "' is not a catchpad"); - return nullptr; - } - break; - case OC_CleanupPad: - if (!isa(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 @@ // 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 @@ // 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(Val)) { - P.Error(Loc, "'%" + Twine(ID) + "' is not a catchpad"); - return nullptr; - } - break; - case OC_CleanupPad: - if (!isa(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 @@ // 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 @@ 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(Sentinel)) { - if (!isa(Inst)) - return P.Error(FI->second.second, - "'%" + Twine(NameID) + "' is not a catchpad"); - } else if (isa(Sentinel)) { - if (!isa(Inst)) - return P.Error(FI->second.second, - "'%" + Twine(NameID) + "' is not a cleanuppad"); - } Sentinel->replaceAllUsesWith(Inst); delete Sentinel; @@ -2515,17 +2442,6 @@ 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(Sentinel)) { - if (!isa(Inst)) - return P.Error(FI->second.second, - "'%" + NameStr + "' is not a catchpad"); - } else if (isa(Sentinel)) { - if (!isa(Inst)) - return P.Error(FI->second.second, - "'%" + NameStr + "' is not a cleanuppad"); - } Sentinel->replaceAllUsesWith(Inst); delete Sentinel; @@ -4235,30 +4151,18 @@ //===----------------------------------------------------------------------===// 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::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 @@ 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 @@ } /// 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 @@ } } - Inst = CleanupReturnInst::Create(cast(CleanupPad), UnwindBB); + Inst = CleanupReturnInst::Create(CleanupPad, UnwindBB); return false; } /// ParseCatchRet -/// ::= 'catchret' Value 'to' TypeAndValue +/// ::= 'catchret' from Parent Value 'to' TypeAndValue bool LLParser::ParseCatchRet(Instruction *&Inst, PerFunctionState &PFS) { Value *CatchPad = nullptr; - if (ParseValue(Type::getTokenTy(Context), CatchPad, PFS, OC_CatchPad)) + if (ParseToken(lltok::kw_from, "expected 'from' after catchret")) + return true; + + if (ParseValue(Type::getTokenTy(Context), CatchPad, PFS)) return true; BasicBlock *BB; @@ -5300,114 +5208,140 @@ ParseTypeAndBasicBlock(BB, PFS)) return true; - Inst = CatchReturnInst::Create(cast(CatchPad), BB); + Inst = CatchReturnInst::Create(CatchPad, BB); return false; } -/// ParseCatchPad -/// ::= 'catchpad' ParamList 'to' TypeAndValue 'unwind' TypeAndValue -bool LLParser::ParseCatchPad(Instruction *&Inst, PerFunctionState &PFS) { - SmallVector Args; - if (ParseExceptionArgs(Args, PFS)) +/// ParseCatchSwitch +/// ::= 'catchswitch' within Parent +bool LLParser::ParseCatchSwitch(Instruction *&Inst, PerFunctionState &PFS) { + Value *OuterScope; + LocTy BBLoc; + + if (ParseToken(lltok::kw_within, "expected 'within' after catchswitch")) return true; - BasicBlock *NormalBB, *UnwindBB; - if (ParseToken(lltok::kw_to, "expected 'to' in catchpad") || - ParseTypeAndBasicBlock(NormalBB, PFS) || - ParseToken(lltok::kw_unwind, "expected 'unwind' in catchpad") || - ParseTypeAndBasicBlock(UnwindBB, PFS)) + if (Lex.getKind() != lltok::kw_none && Lex.getKind() != lltok::LocalVar && + Lex.getKind() != lltok::LocalVarID) + return TokError("expected scope value for catchswitch"); + + if (ParseValue(Type::getTokenTy(Context), OuterScope, PFS)) return true; - Inst = CatchPadInst::Create(NormalBB, UnwindBB, Args); - return false; -} + if (ParseToken(lltok::lsquare, "expected '[' with catchswitch labels")) + return true; -/// ParseTerminatePad -/// ::= 'terminatepad' ParamList 'to' TypeAndValue -bool LLParser::ParseTerminatePad(Instruction *&Inst, PerFunctionState &PFS) { - SmallVector Args; - if (ParseExceptionArgs(Args, PFS)) + SmallVector Table; + do { + BasicBlock *DestBB; + if (ParseTypeAndBasicBlock(DestBB, PFS)) + return true; + Table.push_back(DestBB); + } while (EatIfPresent(lltok::comma)); + + if (ParseToken(lltok::rsquare, "expected ']' after catchswitch labels")) return true; - if (ParseToken(lltok::kw_unwind, "expected 'unwind' in terminatepad")) + if (ParseToken(lltok::kw_unwind, + "expected 'unwind' after catchswitch scope")) return true; BasicBlock *UnwindBB = nullptr; - if (Lex.getKind() == lltok::kw_to) { - Lex.Lex(); - if (ParseToken(lltok::kw_caller, "expected 'caller' in terminatepad")) + if (EatIfPresent(lltok::kw_to)) { + if (ParseToken(lltok::kw_caller, "expected 'caller' in catchswitch")) return true; } else { - if (ParseTypeAndBasicBlock(UnwindBB, PFS)) { + if (ParseTypeAndBasicBlock(UnwindBB, PFS)) return true; - } } - Inst = TerminatePadInst::Create(Context, UnwindBB, Args); + auto *CatchSwitch = + CatchSwitchInst::Create(OuterScope, UnwindBB, Table.size()); + for (BasicBlock *DestBB : Table) + CatchSwitch->addHandler(DestBB); + Inst = CatchSwitch; return false; } -/// ParseCleanupPad -/// ::= 'cleanuppad' ParamList -bool LLParser::ParseCleanupPad(Instruction *&Inst, PerFunctionState &PFS) { +/// ParseCatchPad +/// ::= 'catchpad' ParamList 'to' TypeAndValue 'unwind' TypeAndValue +bool LLParser::ParseCatchPad(Instruction *&Inst, PerFunctionState &PFS) { + Value *CatchSwitch = nullptr; + + if (ParseToken(lltok::kw_within, "expected 'within' after catchpad")) + return true; + + if (Lex.getKind() != lltok::LocalVar && Lex.getKind() != lltok::LocalVarID) + return TokError("expected scope value for catchpad"); + + if (ParseValue(Type::getTokenTy(Context), CatchSwitch, PFS)) + return true; + SmallVector Args; if (ParseExceptionArgs(Args, PFS)) return true; - Inst = CleanupPadInst::Create(Context, Args); + Inst = CatchPadInst::Create(CatchSwitch, Args); return false; } -/// ParseCatchEndPad -/// ::= 'catchendpad' unwind ('to' 'caller' | TypeAndValue) -bool LLParser::ParseCatchEndPad(Instruction *&Inst, PerFunctionState &PFS) { - if (ParseToken(lltok::kw_unwind, "expected 'unwind' in catchendpad")) +/// ParseTerminatePad +/// ::= 'terminatepad' within Parent ParamList 'to' TypeAndValue +bool LLParser::ParseTerminatePad(Instruction *&Inst, PerFunctionState &PFS) { + Value *OuterScope = 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), OuterScope, PFS)) + return true; + + SmallVector Args; + if (ParseExceptionArgs(Args, PFS)) + return true; + + if (ParseToken(lltok::kw_unwind, "expected 'unwind' in terminatepad")) return true; BasicBlock *UnwindBB = nullptr; if (Lex.getKind() == lltok::kw_to) { Lex.Lex(); - if (Lex.getKind() == lltok::kw_caller) { - Lex.Lex(); - } else { + if (ParseToken(lltok::kw_caller, "expected 'caller' in terminatepad")) return true; - } } else { if (ParseTypeAndBasicBlock(UnwindBB, PFS)) { return true; } } - Inst = CatchEndPadInst::Create(Context, UnwindBB); + Inst = TerminatePadInst::Create(OuterScope, UnwindBB, Args); return false; } -/// ParseCatchEndPad -/// ::= 'cleanupendpad' Value unwind ('to' 'caller' | TypeAndValue) -bool LLParser::ParseCleanupEndPad(Instruction *&Inst, PerFunctionState &PFS) { - Value *CleanupPad = nullptr; +/// ParseCleanupPad +/// ::= 'cleanuppad' within Parent ParamList +bool LLParser::ParseCleanupPad(Instruction *&Inst, PerFunctionState &PFS) { + Value *OuterScope = nullptr; - if (ParseValue(Type::getTokenTy(Context), CleanupPad, PFS, OC_CleanupPad)) + if (ParseToken(lltok::kw_within, "expected 'within' after cleanuppad")) return true; - if (ParseToken(lltok::kw_unwind, "expected 'unwind' in catchendpad")) + if (Lex.getKind() != lltok::kw_none && Lex.getKind() != lltok::LocalVar && + Lex.getKind() != lltok::LocalVarID) + return TokError("expected scope value for cleanuppad"); + + if (ParseValue(Type::getTokenTy(Context), OuterScope, PFS)) return true; - BasicBlock *UnwindBB = nullptr; - if (Lex.getKind() == lltok::kw_to) { - Lex.Lex(); - if (Lex.getKind() == lltok::kw_caller) { - Lex.Lex(); - } else { - return true; - } - } else { - if (ParseTypeAndBasicBlock(UnwindBB, PFS)) { - return true; - } - } + SmallVector Args; + if (ParseExceptionArgs(Args, PFS)) + return true; - Inst = CleanupEndPadInst::Create(cast(CleanupPad), UnwindBB); + Inst = CleanupPadInst::Create(OuterScope, Args); return false; } Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -52,6 +52,8 @@ kw_undef, kw_null, kw_none, kw_to, kw_caller, + kw_within, + kw_from, kw_tail, kw_musttail, kw_notail, @@ -182,8 +184,8 @@ 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, Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -42,14 +42,6 @@ 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 ValuePtrs; @@ -93,10 +85,9 @@ } 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 @@ 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 @@ /// past the number of slots used by the value in the record. Return true if /// there is an error. bool popValue(SmallVectorImpl &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 @@ /// Like popValue, but does not increment the Slot number. bool getValue(SmallVectorImpl &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 &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 &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 @@ 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 @@ 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 @@ } 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(PrevVal)) { - if (!isa(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(PrevVal)) { - if (!isa(V)) - return true; - } OldV->replaceAllUsesWith(V); delete PrevVal; } - return false; + return; } @@ -961,8 +933,7 @@ 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 @@ // 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(V); - case OC_CleanupPad: - return dyn_cast(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 @@ } } - if (ValueList.assignValue(V, NextCstNo)) - return error("Invalid forward reference"); + ValueList.assignValue(V, NextCstNo); ++NextCstNo; } } @@ -4470,8 +4415,8 @@ 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 @@ return error("Invalid record"); } - I = CleanupReturnInst::Create(cast(CleanupPad), - UnwindDest); + I = CleanupReturnInst::Create(CleanupPad, UnwindDest); InstructionList.push_back(I); break; } @@ -4490,57 +4434,67 @@ 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(CatchPad), BB); + I = CatchReturnInst::Create(CatchPad, BB); InstructionList.push_back(I); break; } - case bitc::FUNC_CODE_INST_CATCHPAD: { // CATCHPAD: [bb#,bb#,num,(ty,val)*] - if (Record.size() < 3) + case bitc::FUNC_CODE_INST_CATCHSWITCH: { // CATCHSWITCH: [tok,num,(bb)*,bb?] + // We must have, at minimum, the outer scope and the number of arguments. + if (Record.size() < 2) return error("Invalid record"); + unsigned Idx = 0; - BasicBlock *NormalBB = getBasicBlock(Record[Idx++]); - if (!NormalBB) - return error("Invalid record"); - BasicBlock *UnwindBB = getBasicBlock(Record[Idx++]); - if (!UnwindBB) - return error("Invalid record"); - unsigned NumArgOperands = Record[Idx++]; - SmallVector Args; - for (unsigned Op = 0; Op != NumArgOperands; ++Op) { - Value *Val; - if (getValueTypePair(Record, Idx, NextValueNo, Val)) + + Value *OuterScope = + getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); + + unsigned NumHandlers = Record[Idx++]; + + SmallVector Handlers; + for (unsigned Op = 0; Op != NumHandlers; ++Op) { + BasicBlock *BB = getBasicBlock(Record[Idx++]); + if (!BB) + return error("Invalid record"); + Handlers.push_back(BB); + } + + BasicBlock *UnwindDest = nullptr; + if (Idx + 1 == Record.size()) { + UnwindDest = getBasicBlock(Record[Idx++]); + if (!UnwindDest) return error("Invalid record"); - Args.push_back(Val); } + if (Record.size() != Idx) return error("Invalid record"); - I = CatchPadInst::Create(NormalBB, UnwindBB, Args); + auto *CatchSwitch = CatchSwitchInst::Create(OuterScope, UnwindDest, NumHandlers); + for (BasicBlock *Handler : Handlers) + CatchSwitch->addHandler(Handler); + I = CatchSwitch; InstructionList.push_back(I); break; } - case bitc::FUNC_CODE_INST_TERMINATEPAD: { // TERMINATEPAD: [bb#,num,(ty,val)*] - if (Record.size() < 1) + case bitc::FUNC_CODE_INST_TERMINATEPAD: { // TERMINATEPAD: [tok,bb#,num,(ty,val)*] + // We must have, at minimum, the outer scope and the number of arguments. + if (Record.size() < 2) return error("Invalid record"); + unsigned Idx = 0; - bool HasUnwindDest = !!Record[Idx++]; - BasicBlock *UnwindDest = nullptr; - if (HasUnwindDest) { - if (Idx == Record.size()) - return error("Invalid record"); - UnwindDest = getBasicBlock(Record[Idx++]); - if (!UnwindDest) - return error("Invalid record"); - } + + Value *OuterScope = + getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); + unsigned NumArgOperands = Record[Idx++]; + SmallVector Args; for (unsigned Op = 0; Op != NumArgOperands; ++Op) { Value *Val; @@ -4548,18 +4502,34 @@ 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(OuterScope, 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 *OuterScope = + getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); + unsigned NumArgOperands = Record[Idx++]; + SmallVector Args; for (unsigned Op = 0; Op != NumArgOperands; ++Op) { Value *Val; @@ -4567,42 +4537,14 @@ return error("Invalid record"); Args.push_back(Val); } - if (Record.size() != Idx) - return error("Invalid record"); - I = CleanupPadInst::Create(Context, Args); - InstructionList.push_back(I); - break; - } - case bitc::FUNC_CODE_INST_CATCHENDPAD: { // CATCHENDPADINST: [bb#] or [] - if (Record.size() > 1) - return error("Invalid record"); - BasicBlock *BB = nullptr; - if (Record.size() == 1) { - BB = getBasicBlock(Record[0]); - if (!BB) - return error("Invalid record"); - } - I = CatchEndPadInst::Create(Context, BB); - InstructionList.push_back(I); - break; - } - case bitc::FUNC_CODE_INST_CLEANUPENDPAD: { // CLEANUPENDPADINST: [val] or [val,bb#] - if (Record.size() != 1 && Record.size() != 2) - return error("Invalid record"); - unsigned Idx = 0; - Value *CleanupPad = getValue(Record, Idx++, NextValueNo, - Type::getTokenTy(Context), OC_CleanupPad); - if (!CleanupPad) + if (Record.size() != Idx) return error("Invalid record"); - BasicBlock *BB = nullptr; - if (Record.size() == 2) { - BB = getBasicBlock(Record[Idx++]); - if (!BB) - return error("Invalid record"); - } - I = CleanupEndPadInst::Create(cast(CleanupPad), BB); + if (BitCode == bitc::FUNC_CODE_INST_CLEANUPPAD) + I = CleanupPadInst::Create(OuterScope, Args); + else + I = CatchPadInst::Create(OuterScope, Args); InstructionList.push_back(I); break; } @@ -5224,8 +5166,7 @@ // 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: Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1997,51 +1997,47 @@ Vals.push_back(VE.getValueID(CRI.getSuccessor())); break; } + case Instruction::CleanupPad: case Instruction::CatchPad: { - Code = bitc::FUNC_CODE_INST_CATCHPAD; - const auto &CPI = cast(I); - Vals.push_back(VE.getValueID(CPI.getNormalDest())); - Vals.push_back(VE.getValueID(CPI.getUnwindDest())); - unsigned NumArgOperands = CPI.getNumArgOperands(); + const auto &FuncletPad = cast(I); + Code = isa(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(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(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(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(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(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: Index: lib/CodeGen/AsmPrinter/WinException.cpp =================================================================== --- lib/CodeGen/AsmPrinter/WinException.cpp +++ lib/CodeGen/AsmPrinter/WinException.cpp @@ -344,42 +344,32 @@ 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 - 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 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 @@ MachineBasicBlock::const_iterator MBBI; InvokeStateChange LastStateChange; bool VisitingInvoke = false; + int BaseState; }; } // end anonymous namespace @@ -421,14 +412,14 @@ 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 @@ 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 @@ } } // 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::computeIP2StateTable( const MachineFunction *MF, const WinEHFuncInfo &FuncInfo, SmallVectorImpl> &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(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. + } } } Index: lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp =================================================================== --- lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -225,12 +225,12 @@ MMI.setHasEHFunclets(true); MF->getFrameInfo()->setHasOpaqueSPAdjustment(true); } - if (isa(I) || isa(I)) { + if (isa(I)) { assert(&*BB->begin() == I && "WinEHPrepare failed to remove PHIs from imaginary BBs"); continue; } - if (isa(I) || isa(I)) + if (isa(I)) assert(&*BB->begin() == I && "WinEHPrepare failed to demote PHIs"); } Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h @@ -736,9 +736,8 @@ 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); Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -1184,21 +1184,7 @@ 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 @@ 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 @@ /// 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 @@ UnwindDests.emplace_back(FuncInfo.MBBMap[EHPadBB], Prob); UnwindDests.back().first->setIsEHFuncletEntry(); break; - } else if (const auto *CPI = dyn_cast(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(Pad)) - NewEHPadBB = CEPI->getUnwindDest(); - else if (const auto *CEPI = dyn_cast(Pad)) - NewEHPadBB = CEPI->getUnwindDest(); - else + } else if (auto *CatchSwitch = dyn_cast(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 @@ 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::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); @@ -5355,8 +5336,10 @@ // Inform MachineModuleInfo of range. if (MMI.hasEHFunclets()) { + assert(CLI.CS); WinEHFuncInfo *EHInfo = DAG.getMachineFunction().getWinEHFuncInfo(); - EHInfo->addIPToStateRange(EHPadBB, BeginLabel, EndLabel); + EHInfo->addIPToStateRange(cast(CLI.CS->getInstruction()), + BeginLabel, EndLabel); } else { MMI.addInvoke(FuncInfo.MBBMap[EHPadBB], BeginLabel, EndLabel); } Index: lib/CodeGen/TargetLoweringBase.cpp =================================================================== --- lib/CodeGen/TargetLoweringBase.cpp +++ lib/CodeGen/TargetLoweringBase.cpp @@ -1571,13 +1571,12 @@ 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; Index: lib/CodeGen/WinEHPrepare.cpp =================================================================== --- lib/CodeGen/WinEHPrepare.cpp +++ lib/CodeGen/WinEHPrepare.cpp @@ -17,7 +17,7 @@ //===----------------------------------------------------------------------===// #include "llvm/CodeGen/Passes.h" -#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/MapVector.h" #include "llvm/Analysis/CFG.h" #include "llvm/Analysis/EHPersonalities.h" #include "llvm/CodeGen/WinEHFuncInfo.h" @@ -69,27 +69,12 @@ AllocaInst *insertPHILoads(PHINode *PN, Function &F); void replaceUseWithLoad(Value *V, Use &U, AllocaInst *&SpillSlot, DenseMap &Loads, Function &F); - bool prepareExplicitEH(Function &F, - SmallVectorImpl &EntryBlocks); + bool prepareExplicitEH(Function &F); void replaceTerminatePadWithCleanup(Function &F); - void colorFunclets(Function &F, SmallVectorImpl &EntryBlocks); - void resolveFuncletAncestry(Function &F, - SmallVectorImpl &EntryBlocks); - void resolveFuncletAncestryForPath( - Function &F, SmallVectorImpl &FuncletPath, - std::map &IdentityMap); - void makeFuncletEdgeUnreachable(BasicBlock *Parent, BasicBlock *Child); - BasicBlock *cloneFuncletForParent(Function &F, BasicBlock *FuncletEntry, - BasicBlock *Parent); - void updateTerminatorsAfterFuncletClone( - Function &F, BasicBlock *OrigFunclet, BasicBlock *CloneFunclet, - BasicBlock *OrigBlock, BasicBlock *CloneBlock, BasicBlock *CloneParent, - ValueToValueMapTy &VMap, - std::map &Orig2Clone); + void colorFunclets(Function &F); void demotePHIsOnFunclets(Function &F); - void cloneCommonBlocks(Function &F, - SmallVectorImpl &EntryBlocks); + void cloneCommonBlocks(Function &F); void removeImplausibleTerminators(Function &F); void cleanupPreparedFunclets(Function &F); void verifyPreparedFunclets(Function &F); @@ -97,20 +82,8 @@ // All fields are reset by runOnFunction. EHPersonality Personality = EHPersonality::Unknown; - std::map> BlockColors; - std::map> FuncletBlocks; - std::map> FuncletChildren; - std::map> FuncletParents; - - // This is a flag that indicates an uncommon situation where we need to - // clone funclets has been detected. - bool FuncletCloningRequired = false; - // When a funclet with multiple parents contains a catchret, the block to - // which it returns will be cloned so that there is a copy in each parent - // but one of the copies will not be properly linked to the catchret and - // in most cases will have no predecessors. This double map allows us - // to find these cloned blocks when we clone the child funclet. - std::map> EstrangedBlocks; + DenseMap BlockColors; + MapVector> FuncletBlocks; }; } // end anonymous namespace @@ -123,21 +96,6 @@ return new WinEHPrepare(TM); } -static void findFuncletEntryPoints(Function &Fn, - SmallVectorImpl &EntryBlocks) { - EntryBlocks.push_back(&Fn.getEntryBlock()); - for (BasicBlock &BB : Fn) { - Instruction *First = BB.getFirstNonPHI(); - if (!First->isEHPad()) - continue; - assert(!isa(First) && - "landingpad cannot be used with funclet EH personality"); - // Find EH pad blocks that represent funclet start points. - if (!isa(First) && !isa(First)) - EntryBlocks.push_back(&BB); - } -} - bool WinEHPrepare::runOnFunction(Function &Fn) { if (!Fn.hasPersonalityFn()) return false; @@ -149,14 +107,7 @@ if (!isFuncletEHPersonality(Personality)) return false; - // Remove unreachable blocks. It is not valuable to assign them a color and - // their existence can trick us into thinking values are alive when they are - // not. - removeUnreachableBlocks(Fn); - - SmallVector EntryBlocks; - findFuncletEntryPoints(Fn, EntryBlocks); - return prepareExplicitEH(Fn, EntryBlocks); + return prepareExplicitEH(Fn); } bool WinEHPrepare::doFinalization(Module &M) { return false; } @@ -198,117 +149,142 @@ FuncInfo.TryBlockMap.push_back(TBME); } -static const CatchPadInst *getSingleCatchPadPredecessor(const BasicBlock *BB) { - for (const BasicBlock *PredBlock : predecessors(BB)) - if (auto *CPI = dyn_cast(PredBlock->getFirstNonPHI())) - return CPI; +static BasicBlock *getCleanupRetUnwindDest(const CleanupPadInst *CleanupPad) { + for (const User *U : CleanupPad->users()) + if (const auto *CRI = dyn_cast(U)) + return CRI->getUnwindDest(); return nullptr; } -/// Find all the catchpads that feed directly into the catchendpad. Frontends -/// using this personality should ensure that each catchendpad and catchpad has -/// one or zero catchpad predecessors. -/// -/// The following C++ generates the IR after it: -/// try { -/// } catch (A) { -/// } catch (B) { -/// } -/// -/// IR: -/// %catchpad.A -/// catchpad [i8* A typeinfo] -/// to label %catch.A unwind label %catchpad.B -/// %catchpad.B -/// catchpad [i8* B typeinfo] -/// to label %catch.B unwind label %endcatches -/// %endcatches -/// catchendblock unwind to caller -static void -findCatchPadsForCatchEndPad(const BasicBlock *CatchEndBB, - SmallVectorImpl &Handlers) { - const CatchPadInst *CPI = getSingleCatchPadPredecessor(CatchEndBB); - while (CPI) { - Handlers.push_back(CPI); - CPI = getSingleCatchPadPredecessor(CPI->getParent()); +static void calculateStateNumbersForInvokes(const Function *Fn, + WinEHFuncInfo &FuncInfo) { + auto *F = const_cast(Fn); + DenseMap BlockColors = colorEHFunclets(*F); + for (BasicBlock &BB : *F) { + auto *II = dyn_cast(BB.getTerminator()); + if (!II) + continue; + + auto &BBColors = BlockColors[&BB]; + assert(BBColors.size() == 1 && + "multi-color BB not removed by preparation"); + BasicBlock *FuncletEntryBB = BBColors.front(); + + BasicBlock *FuncletUnwindDest; + auto *FuncletPad = + dyn_cast(FuncletEntryBB->getFirstNonPHI()); + assert(FuncletPad || FuncletEntryBB == &Fn->getEntryBlock()); + if (!FuncletPad) + FuncletUnwindDest = nullptr; + else if (auto *CatchPad = dyn_cast(FuncletPad)) + FuncletUnwindDest = CatchPad->getCatchSwitch()->getUnwindDest(); + else if (auto *CleanupPad = dyn_cast(FuncletPad)) + FuncletUnwindDest = getCleanupRetUnwindDest(CleanupPad); + else + llvm_unreachable("unexpected funclet pad!"); + + BasicBlock *InvokeUnwindDest = II->getUnwindDest(); + int BaseState = -1; + if (FuncletUnwindDest == InvokeUnwindDest) { + auto BaseStateI = FuncInfo.FuncletBaseStateMap.find(FuncletPad); + if (BaseStateI != FuncInfo.FuncletBaseStateMap.end()) + BaseState = BaseStateI->second; + } + + if (BaseState != -1) { + FuncInfo.InvokeStateMap[II] = BaseState; + } else { + Instruction *PadInst = InvokeUnwindDest->getFirstNonPHI(); + assert(FuncInfo.EHPadStateMap.count(PadInst) && "EH Pad has no state!"); + FuncInfo.InvokeStateMap[II] = FuncInfo.EHPadStateMap[PadInst]; + } } - // We've pushed these back into reverse source order. Reverse them to get - // the list back into source order. - std::reverse(Handlers.begin(), Handlers.end()); } // Given BB which ends in an unwind edge, return the EHPad that this BB belongs // to. If the unwind edge came from an invoke, return null. -static const BasicBlock *getEHPadFromPredecessor(const BasicBlock *BB) { +static const BasicBlock *getEHPadFromPredecessor(const BasicBlock *BB, + Value *OuterScope) { const TerminatorInst *TI = BB->getTerminator(); if (isa(TI)) return nullptr; - if (TI->isEHPad()) + if (auto *CatchSwitch = dyn_cast(TI)) { + if (CatchSwitch->getParentPad() != OuterScope) + return nullptr; return BB; - return cast(TI)->getCleanupPad()->getParent(); + } + assert(!TI->isEHPad() && "unexpected EHPad!"); + auto *CleanupPad = cast(TI)->getCleanupPad(); + if (CleanupPad->getParentPad() != OuterScope) + return nullptr; + return CleanupPad->getParent(); } -static void calculateExplicitCXXStateNumbers(WinEHFuncInfo &FuncInfo, - const BasicBlock &BB, - int ParentState) { - assert(BB.isEHPad()); - const Instruction *FirstNonPHI = BB.getFirstNonPHI(); - // All catchpad instructions will be handled when we process their - // respective catchendpad instruction. - if (isa(FirstNonPHI)) - return; +static void calculateCXXStateNumbers(WinEHFuncInfo &FuncInfo, + const Instruction *FirstNonPHI, + int ParentState) { + const BasicBlock *BB = FirstNonPHI->getParent(); + assert(BB->isEHPad() && "not a funclet!"); + + if (auto *CatchSwitch = dyn_cast(FirstNonPHI)) { + assert(FuncInfo.EHPadStateMap.count(CatchSwitch) == 0 && + "shouldn't revist catch funclets!"); - if (isa(FirstNonPHI)) { SmallVector Handlers; - findCatchPadsForCatchEndPad(&BB, Handlers); - const BasicBlock *FirstTryPad = Handlers.front()->getParent(); + for (const BasicBlock *CatchPadBB : CatchSwitch->handlers()) { + auto *CatchPad = cast(CatchPadBB->getFirstNonPHI()); + Handlers.push_back(CatchPad); + } int TryLow = addUnwindMapEntry(FuncInfo, ParentState, nullptr); - FuncInfo.EHPadStateMap[Handlers.front()] = TryLow; - for (const BasicBlock *PredBlock : predecessors(FirstTryPad)) - if ((PredBlock = getEHPadFromPredecessor(PredBlock))) - calculateExplicitCXXStateNumbers(FuncInfo, *PredBlock, TryLow); + FuncInfo.EHPadStateMap[CatchSwitch] = TryLow; + for (const BasicBlock *PredBlock : predecessors(BB)) + if ((PredBlock = getEHPadFromPredecessor(PredBlock, + CatchSwitch->getParentPad()))) + calculateCXXStateNumbers(FuncInfo, PredBlock->getFirstNonPHI(), + TryLow); int CatchLow = addUnwindMapEntry(FuncInfo, ParentState, nullptr); // catchpads are separate funclets in C++ EH due to the way rethrow works. - // In SEH, they aren't, so no invokes will unwind to the catchendpad. - FuncInfo.EHPadStateMap[FirstNonPHI] = CatchLow; int TryHigh = CatchLow - 1; - for (const BasicBlock *PredBlock : predecessors(&BB)) - if ((PredBlock = getEHPadFromPredecessor(PredBlock))) - calculateExplicitCXXStateNumbers(FuncInfo, *PredBlock, CatchLow); + for (const auto *CatchPad : Handlers) { + FuncInfo.FuncletBaseStateMap[CatchPad] = CatchLow; + for (const User *U : CatchPad->users()) { + const auto *UserI = cast(U); + if (UserI->isEHPad()) + calculateCXXStateNumbers(FuncInfo, UserI, CatchLow); + } + } int CatchHigh = FuncInfo.getLastStateNumber(); addTryBlockMapEntry(FuncInfo, TryLow, TryHigh, CatchHigh, Handlers); - DEBUG(dbgs() << "TryLow[" << FirstTryPad->getName() << "]: " << TryLow + DEBUG(dbgs() << "TryLow[" << BB->getName() << "]: " << TryLow << '\n'); + DEBUG(dbgs() << "TryHigh[" << BB->getName() << "]: " << TryHigh << '\n'); + DEBUG(dbgs() << "CatchHigh[" << BB->getName() << "]: " << CatchHigh << '\n'); - DEBUG(dbgs() << "TryHigh[" << FirstTryPad->getName() << "]: " << TryHigh - << '\n'); - DEBUG(dbgs() << "CatchHigh[" << FirstTryPad->getName() << "]: " << CatchHigh - << '\n'); - } else if (isa(FirstNonPHI)) { - // A cleanup can have multiple exits; don't re-process after the first. - if (FuncInfo.EHPadStateMap.count(FirstNonPHI)) + } else { + auto *CleanupPad = cast(FirstNonPHI); + + // It's possible for a cleanup to be visited twice: it might have multiple + // cleanupret instructions. + if (FuncInfo.EHPadStateMap.count(CleanupPad)) return; - int CleanupState = addUnwindMapEntry(FuncInfo, ParentState, &BB); - FuncInfo.EHPadStateMap[FirstNonPHI] = CleanupState; + + int CleanupState = addUnwindMapEntry(FuncInfo, ParentState, BB); + FuncInfo.EHPadStateMap[CleanupPad] = CleanupState; DEBUG(dbgs() << "Assigning state #" << CleanupState << " to BB " - << BB.getName() << '\n'); - for (const BasicBlock *PredBlock : predecessors(&BB)) - if ((PredBlock = getEHPadFromPredecessor(PredBlock))) - calculateExplicitCXXStateNumbers(FuncInfo, *PredBlock, CleanupState); - } else if (auto *CEPI = dyn_cast(FirstNonPHI)) { - // Propagate ParentState to the cleanuppad in case it doesn't have - // any cleanuprets. - BasicBlock *CleanupBlock = CEPI->getCleanupPad()->getParent(); - calculateExplicitCXXStateNumbers(FuncInfo, *CleanupBlock, ParentState); - // Anything unwinding through CleanupEndPadInst is in ParentState. - FuncInfo.EHPadStateMap[FirstNonPHI] = ParentState; - for (const BasicBlock *PredBlock : predecessors(&BB)) - if ((PredBlock = getEHPadFromPredecessor(PredBlock))) - calculateExplicitCXXStateNumbers(FuncInfo, *PredBlock, ParentState); - } else if (isa(FirstNonPHI)) { - report_fatal_error("Not yet implemented!"); - } else { - llvm_unreachable("unexpected EH Pad!"); + << BB->getName() << '\n'); + for (const BasicBlock *PredBlock : predecessors(BB)) { + if ((PredBlock = getEHPadFromPredecessor(PredBlock, + CleanupPad->getParentPad()))) { + calculateCXXStateNumbers(FuncInfo, PredBlock->getFirstNonPHI(), + CleanupState); + } + } + for (const User *U : CleanupPad->users()) { + const auto *UserI = cast(U); + if (UserI->isEHPad()) + report_fatal_error("Cleanup funclets for the MSVC++ personality cannot " + "contain exceptional actions"); + } } } @@ -334,94 +310,84 @@ return FuncInfo.SEHUnwindMap.size() - 1; } -static void calculateExplicitSEHStateNumbers(WinEHFuncInfo &FuncInfo, - const BasicBlock &BB, - int ParentState) { - assert(BB.isEHPad()); - const Instruction *FirstNonPHI = BB.getFirstNonPHI(); - // All catchpad instructions will be handled when we process their - // respective catchendpad instruction. - if (isa(FirstNonPHI)) - return; +static void calculateSEHStateNumbers(WinEHFuncInfo &FuncInfo, + const Instruction *FirstNonPHI, + int ParentState) { + const BasicBlock *BB = FirstNonPHI->getParent(); + assert(BB->isEHPad() && "no a funclet!"); + + if (auto *CatchSwitch = dyn_cast(FirstNonPHI)) { + assert(FuncInfo.EHPadStateMap.count(CatchSwitch) == 0 && + "shouldn't revist catch funclets!"); - if (isa(FirstNonPHI)) { // Extract the filter function and the __except basic block and create a // state for them. - SmallVector Handlers; - findCatchPadsForCatchEndPad(&BB, Handlers); - assert(Handlers.size() == 1 && + assert(CatchSwitch->getNumHandlers() == 1 && "SEH doesn't have multiple handlers per __try"); - const CatchPadInst *CPI = Handlers.front(); - const BasicBlock *CatchPadBB = CPI->getParent(); + const auto *CatchPad = + cast((*CatchSwitch->handler_begin())->getFirstNonPHI()); + const BasicBlock *CatchPadBB = CatchPad->getParent(); const Constant *FilterOrNull = - cast(CPI->getArgOperand(0)->stripPointerCasts()); + cast(CatchPad->getArgOperand(0)->stripPointerCasts()); const Function *Filter = dyn_cast(FilterOrNull); assert((Filter || FilterOrNull->isNullValue()) && "unexpected filter value"); int TryState = addSEHExcept(FuncInfo, ParentState, Filter, CatchPadBB); // Everything in the __try block uses TryState as its parent state. - FuncInfo.EHPadStateMap[CPI] = TryState; + FuncInfo.EHPadStateMap[CatchSwitch] = TryState; DEBUG(dbgs() << "Assigning state #" << TryState << " to BB " << CatchPadBB->getName() << '\n'); - for (const BasicBlock *PredBlock : predecessors(CatchPadBB)) - if ((PredBlock = getEHPadFromPredecessor(PredBlock))) - calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, TryState); + for (const BasicBlock *PredBlock : predecessors(BB)) + if ((PredBlock = getEHPadFromPredecessor(PredBlock, + CatchSwitch->getParentPad()))) + calculateSEHStateNumbers(FuncInfo, PredBlock->getFirstNonPHI(), + TryState); // Everything in the __except block unwinds to ParentState, just like code // outside the __try. - FuncInfo.EHPadStateMap[FirstNonPHI] = ParentState; - DEBUG(dbgs() << "Assigning state #" << ParentState << " to BB " - << BB.getName() << '\n'); - for (const BasicBlock *PredBlock : predecessors(&BB)) - if ((PredBlock = getEHPadFromPredecessor(PredBlock))) - calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, ParentState); - } else if (isa(FirstNonPHI)) { - // A cleanup can have multiple exits; don't re-process after the first. - if (FuncInfo.EHPadStateMap.count(FirstNonPHI)) + for (const User *U : CatchPad->users()) { + const auto *UserI = cast(U); + if (UserI->isEHPad()) { + calculateSEHStateNumbers(FuncInfo, UserI, ParentState); + } + } + } else { + auto *CleanupPad = cast(FirstNonPHI); + + // It's possible for a cleanup to be visited twice: it might have multiple + // cleanupret instructions. + if (FuncInfo.EHPadStateMap.count(CleanupPad)) return; - int CleanupState = addSEHFinally(FuncInfo, ParentState, &BB); - FuncInfo.EHPadStateMap[FirstNonPHI] = CleanupState; + + int CleanupState = addSEHFinally(FuncInfo, ParentState, BB); + FuncInfo.EHPadStateMap[CleanupPad] = CleanupState; DEBUG(dbgs() << "Assigning state #" << CleanupState << " to BB " - << BB.getName() << '\n'); - for (const BasicBlock *PredBlock : predecessors(&BB)) - if ((PredBlock = getEHPadFromPredecessor(PredBlock))) - calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, CleanupState); - } else if (auto *CEPI = dyn_cast(FirstNonPHI)) { - // Propagate ParentState to the cleanuppad in case it doesn't have - // any cleanuprets. - BasicBlock *CleanupBlock = CEPI->getCleanupPad()->getParent(); - calculateExplicitSEHStateNumbers(FuncInfo, *CleanupBlock, ParentState); - // Anything unwinding through CleanupEndPadInst is in ParentState. - FuncInfo.EHPadStateMap[FirstNonPHI] = ParentState; - DEBUG(dbgs() << "Assigning state #" << ParentState << " to BB " - << BB.getName() << '\n'); - for (const BasicBlock *PredBlock : predecessors(&BB)) - if ((PredBlock = getEHPadFromPredecessor(PredBlock))) - calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, ParentState); - } else if (isa(FirstNonPHI)) { - report_fatal_error("Not yet implemented!"); - } else { - llvm_unreachable("unexpected EH Pad!"); + << BB->getName() << '\n'); + for (const BasicBlock *PredBlock : predecessors(BB)) + if ((PredBlock = + getEHPadFromPredecessor(PredBlock, CleanupPad->getParentPad()))) + calculateSEHStateNumbers(FuncInfo, PredBlock->getFirstNonPHI(), + CleanupState); + for (const User *U : CleanupPad->users()) { + const auto *UserI = cast(U); + if (UserI->isEHPad()) + report_fatal_error("Cleanup funclets for the SEH personality cannot " + "contain exceptional actions"); + } } } -/// Check if the EH Pad unwinds to caller. Cleanups are a little bit of a -/// special case because we have to look at the cleanupret instruction that uses -/// the cleanuppad. -static bool doesEHPadUnwindToCaller(const Instruction *EHPad) { - auto *CPI = dyn_cast(EHPad); - if (!CPI) - return EHPad->mayThrow(); - - // This cleanup does not return or unwind, so we say it unwinds to caller. - if (CPI->use_empty()) - return true; - - const Instruction *User = CPI->user_back(); - if (auto *CRI = dyn_cast(User)) - return CRI->unwindsToCaller(); - return cast(User)->unwindsToCaller(); +static bool isTopLevelPadForMSVC(const Instruction *EHPad) { + if (auto *CatchSwitch = dyn_cast(EHPad)) + return isa(CatchSwitch->getParentPad()) && + CatchSwitch->unwindsToCaller(); + if (auto *CleanupPad = dyn_cast(EHPad)) + return isa(CleanupPad->getParentPad()) && + getCleanupRetUnwindDest(CleanupPad) == nullptr; + if (isa(EHPad)) + return false; + llvm_unreachable("unexpected EHPad!"); } void llvm::calculateSEHStateNumbers(const Function *Fn, @@ -431,10 +397,15 @@ return; for (const BasicBlock &BB : *Fn) { - if (!BB.isEHPad() || !doesEHPadUnwindToCaller(BB.getFirstNonPHI())) + if (!BB.isEHPad()) + continue; + const Instruction *FirstNonPHI = BB.getFirstNonPHI(); + if (!isTopLevelPadForMSVC(FirstNonPHI)) continue; - calculateExplicitSEHStateNumbers(FuncInfo, BB, -1); + ::calculateSEHStateNumbers(FuncInfo, FirstNonPHI, -1); } + + calculateStateNumbersForInvokes(Fn, FuncInfo); } void llvm::calculateWinCXXEHStateNumbers(const Function *Fn, @@ -446,13 +417,13 @@ for (const BasicBlock &BB : *Fn) { if (!BB.isEHPad()) continue; - if (BB.isLandingPad()) - report_fatal_error("MSVC C++ EH cannot use landingpads"); const Instruction *FirstNonPHI = BB.getFirstNonPHI(); - if (!doesEHPadUnwindToCaller(FirstNonPHI)) + if (!isTopLevelPadForMSVC(FirstNonPHI)) continue; - calculateExplicitCXXStateNumbers(FuncInfo, BB, -1); + calculateCXXStateNumbers(FuncInfo, FirstNonPHI, -1); } + + calculateStateNumbersForInvokes(Fn, FuncInfo); } static int addClrEHHandler(WinEHFuncInfo &FuncInfo, int ParentState, @@ -483,7 +454,7 @@ if (BB.isLandingPad()) report_fatal_error("CoreCLR EH cannot use landingpads"); const Instruction *FirstNonPHI = BB.getFirstNonPHI(); - if (!doesEHPadUnwindToCaller(FirstNonPHI)) + if (!isTopLevelPadForMSVC(FirstNonPHI)) continue; // queue this with sentinel parent state -1 to mean unwind to caller. Worklist.emplace_back(FirstNonPHI, -1); @@ -494,16 +465,11 @@ int ParentState; std::tie(Pad, ParentState) = Worklist.pop_back_val(); + Value *OuterScope; int PredState; - if (const CleanupEndPadInst *EndPad = dyn_cast(Pad)) { - FuncInfo.EHPadStateMap[EndPad] = ParentState; - // Queue the cleanuppad, in case it doesn't have a cleanupret. - Worklist.emplace_back(EndPad->getCleanupPad(), ParentState); - // Preds of the endpad should get the parent state. - PredState = ParentState; - } else if (const CleanupPadInst *Cleanup = dyn_cast(Pad)) { + if (const CleanupPadInst *Cleanup = dyn_cast(Pad)) { // A cleanup can have multiple exits; don't re-process after the first. - if (FuncInfo.EHPadStateMap.count(Pad)) + if (FuncInfo.EHPadStateMap.count(Cleanup)) continue; // CoreCLR personality uses arity to distinguish faults from finallies. const BasicBlock *PadBlock = Cleanup->getParent(); @@ -514,30 +480,47 @@ addClrEHHandler(FuncInfo, ParentState, HandlerType, 0, PadBlock); FuncInfo.EHPadStateMap[Cleanup] = NewState; // Propagate the new state to all preds of the cleanup + OuterScope = Cleanup->getParentPad(); PredState = NewState; - } else if (const CatchEndPadInst *EndPad = dyn_cast(Pad)) { - FuncInfo.EHPadStateMap[EndPad] = ParentState; - // Preds of the endpad should get the parent state. - PredState = ParentState; - } else if (const CatchPadInst *Catch = dyn_cast(Pad)) { - const BasicBlock *PadBlock = Catch->getParent(); - uint32_t TypeToken = static_cast( - cast(Catch->getArgOperand(0))->getZExtValue()); - int NewState = addClrEHHandler(FuncInfo, ParentState, - ClrHandlerType::Catch, TypeToken, PadBlock); - FuncInfo.EHPadStateMap[Catch] = NewState; - // Preds of the catch get its state + } else if (const auto *CatchSwitch = dyn_cast(Pad)) { + SmallVector Handlers; + for (const BasicBlock *CatchPadBB : CatchSwitch->handlers()) { + const auto *Catch = cast(CatchPadBB->getFirstNonPHI()); + Handlers.push_back(Catch); + } + FuncInfo.EHPadStateMap[CatchSwitch] = ParentState; + int NewState = ParentState; + for (auto HandlerI = Handlers.rbegin(), HandlerE = Handlers.rend(); + HandlerI != HandlerE; ++HandlerI) { + const CatchPadInst *Catch = *HandlerI; + const BasicBlock *PadBlock = Catch->getParent(); + uint32_t TypeToken = static_cast( + cast(Catch->getArgOperand(0))->getZExtValue()); + NewState = addClrEHHandler(FuncInfo, NewState, ClrHandlerType::Catch, + TypeToken, PadBlock); + FuncInfo.EHPadStateMap[Catch] = NewState; + } + for (const auto *CatchPad : Handlers) { + for (const User *U : CatchPad->users()) { + const auto *UserI = cast(U); + if (UserI->isEHPad()) + Worklist.emplace_back(UserI, ParentState); + } + } PredState = NewState; + OuterScope = CatchSwitch->getParentPad(); } else { llvm_unreachable("Unexpected EH pad"); } // Queue all predecessors with the given state for (const BasicBlock *Pred : predecessors(Pad->getParent())) { - if ((Pred = getEHPadFromPredecessor(Pred))) + if ((Pred = getEHPadFromPredecessor(Pred, OuterScope))) Worklist.emplace_back(Pred->getFirstNonPHI(), PredState); } } + + calculateStateNumbersForInvokes(Fn, FuncInfo); } void WinEHPrepare::replaceTerminatePadWithCleanup(Function &F) { @@ -559,8 +542,9 @@ "C++ personalities!"); // Insert the cleanuppad instruction. - auto *CPI = CleanupPadInst::Create( - BB.getContext(), {}, Twine("terminatepad.for.", BB.getName()), &BB); + auto *CPI = + CleanupPadInst::Create(TPI->getParentPad(), {}, + Twine("terminatepad.for.", BB.getName()), &BB); // Insert the call to the terminate instruction. auto *CallTerminate = CallInst::Create(TerminateFn, {}, &BB); @@ -578,980 +562,32 @@ } } -static void -colorFunclets(Function &F, SmallVectorImpl &EntryBlocks, - std::map> &BlockColors, - std::map> &FuncletBlocks) { - SmallVector, 16> Worklist; - BasicBlock *EntryBlock = &F.getEntryBlock(); - - // Build up the color map, which maps each block to its set of 'colors'. - // For any block B, the "colors" of B are the set of funclets F (possibly - // including a root "funclet" representing the main function), such that - // F will need to directly contain B or a copy of B (where the term "directly - // contain" is used to distinguish from being "transitively contained" in - // a nested funclet). - // Use a CFG walk driven by a worklist of (block, color) pairs. The "color" - // sets attached during this processing to a block which is the entry of some - // funclet F is actually the set of F's parents -- i.e. the union of colors - // of all predecessors of F's entry. For all other blocks, the color sets - // are as defined above. A post-pass fixes up the block color map to reflect - // the same sense of "color" for funclet entries as for other blocks. - - DEBUG_WITH_TYPE("winehprepare-coloring", dbgs() << "\nColoring funclets for " - << F.getName() << "\n"); - - Worklist.push_back({EntryBlock, EntryBlock}); - - while (!Worklist.empty()) { - BasicBlock *Visiting; - BasicBlock *Color; - std::tie(Visiting, Color) = Worklist.pop_back_val(); - DEBUG_WITH_TYPE("winehprepare-coloring", - dbgs() << "Visiting " << Visiting->getName() << ", " - << Color->getName() << "\n"); - Instruction *VisitingHead = Visiting->getFirstNonPHI(); - if (VisitingHead->isEHPad() && !isa(VisitingHead) && - !isa(VisitingHead)) { - // Mark this as a funclet head as a member of itself. - FuncletBlocks[Visiting].insert(Visiting); - // Queue exits (i.e. successors of rets/endpads) with the parent color. - // Skip any exits that are catchendpads, since the parent color must then - // represent one of the catches chained to that catchendpad, but the - // catchendpad should get the color of the common parent of all its - // chained catches (i.e. the grandparent color of the current pad). - // We don't need to worry abou catchendpads going unvisited, since the - // catches chained to them must have unwind edges to them by which we will - // visit them. - for (User *U : VisitingHead->users()) { - if (auto *Exit = dyn_cast(U)) { - for (BasicBlock *Succ : successors(Exit->getParent())) - if (!isa(*Succ->getFirstNonPHI())) - if (BlockColors[Succ].insert(Color)) { - DEBUG_WITH_TYPE("winehprepare-coloring", - dbgs() << " Assigned color \'" - << Color->getName() << "\' to block \'" - << Succ->getName() << "\'.\n"); - Worklist.push_back({Succ, Color}); - } - } - } - // Handle CatchPad specially since its successors need different colors. - if (CatchPadInst *CatchPad = dyn_cast(VisitingHead)) { - // Visit the normal successor with the color of the new EH pad, and - // visit the unwind successor with the color of the parent. - BasicBlock *NormalSucc = CatchPad->getNormalDest(); - if (BlockColors[NormalSucc].insert(Visiting)) { - DEBUG_WITH_TYPE("winehprepare-coloring", - dbgs() << " Assigned color \'" << Visiting->getName() - << "\' to block \'" << NormalSucc->getName() - << "\'.\n"); - Worklist.push_back({NormalSucc, Visiting}); - } - BasicBlock *UnwindSucc = CatchPad->getUnwindDest(); - if (BlockColors[UnwindSucc].insert(Color)) { - DEBUG_WITH_TYPE("winehprepare-coloring", - dbgs() << " Assigned color \'" << Color->getName() - << "\' to block \'" << UnwindSucc->getName() - << "\'.\n"); - Worklist.push_back({UnwindSucc, Color}); - } - continue; - } - // Switch color to the current node, except for terminate pads which - // have no bodies and only unwind successors and so need their successors - // visited with the color of the parent. - if (!isa(VisitingHead)) - Color = Visiting; - } else { - // Note that this is a member of the given color. - FuncletBlocks[Color].insert(Visiting); - } - - TerminatorInst *Terminator = Visiting->getTerminator(); - if (isa(Terminator) || - isa(Terminator) || - isa(Terminator)) { - // These blocks' successors have already been queued with the parent - // color. - continue; - } - for (BasicBlock *Succ : successors(Visiting)) { - if (isa(Succ->getFirstNonPHI())) { - // The catchendpad needs to be visited with the parent's color, not - // the current color. This will happen in the code above that visits - // any catchpad unwind successor with the parent color, so we can - // safely skip this successor here. - continue; - } - if (BlockColors[Succ].insert(Color)) { - DEBUG_WITH_TYPE("winehprepare-coloring", - dbgs() << " Assigned color \'" << Color->getName() - << "\' to block \'" << Succ->getName() - << "\'.\n"); - Worklist.push_back({Succ, Color}); - } - } - } -} - -static BasicBlock *getEndPadForCatch(CatchPadInst *Catch) { - // The catch may have sibling catches. Follow the unwind chain until we get - // to the catchendpad. - BasicBlock *NextUnwindDest = Catch->getUnwindDest(); - auto *UnwindTerminator = NextUnwindDest->getTerminator(); - while (auto *NextCatch = dyn_cast(UnwindTerminator)) { - NextUnwindDest = NextCatch->getUnwindDest(); - UnwindTerminator = NextUnwindDest->getTerminator(); - } - // The last catch in the chain must unwind to a catchendpad. - assert(isa(UnwindTerminator)); - return NextUnwindDest; -} - -static void updateClonedEHPadUnwindToParent( - BasicBlock *UnwindDest, BasicBlock *OrigBlock, BasicBlock *CloneBlock, - std::vector &OrigParents, BasicBlock *CloneParent) { - auto updateUnwindTerminator = [](BasicBlock *BB) { - auto *Terminator = BB->getTerminator(); - if (isa(Terminator) || - isa(Terminator)) { - removeUnwindEdge(BB); - } else { - // If the block we're updating has a cleanupendpad or cleanupret - // terminator, we just want to replace that terminator with an - // unreachable instruction. - assert(isa(Terminator) || - isa(Terminator)); - // Loop over all of the successors, removing the block's entry from any - // PHI nodes. - for (succ_iterator SI = succ_begin(BB), SE = succ_end(BB); SI != SE; ++SI) - (*SI)->removePredecessor(BB); - // Remove the terminator and replace it with an unreachable instruction. - BB->getTerminator()->eraseFromParent(); - new UnreachableInst(BB->getContext(), BB); - } - }; - - assert(UnwindDest->isEHPad()); - // There are many places to which this EH terminator can unwind and each has - // slightly different rules for whether or not it fits with the given - // location. - auto *EHPadInst = UnwindDest->getFirstNonPHI(); - if (isa(EHPadInst)) { - auto *CloneParentCatch = - dyn_cast(CloneParent->getFirstNonPHI()); - if (!CloneParentCatch || - getEndPadForCatch(CloneParentCatch) != UnwindDest) { - DEBUG_WITH_TYPE( - "winehprepare-coloring", - dbgs() << " removing unwind destination of clone block \'" - << CloneBlock->getName() << "\'.\n"); - updateUnwindTerminator(CloneBlock); - } - // It's possible that the catch end pad is a legal match for both the clone - // and the original, so they must be checked separately. If the original - // funclet will still have multiple parents after the current clone parent - // is removed, we'll leave its unwind terminator until later. - assert(OrigParents.size() >= 2); - if (OrigParents.size() != 2) - return; - - // If the original funclet will have a single parent after the clone parent - // is removed, check that parent's unwind destination. - assert(OrigParents.front() == CloneParent || - OrigParents.back() == CloneParent); - BasicBlock *OrigParent; - if (OrigParents.front() == CloneParent) - OrigParent = OrigParents.back(); - else - OrigParent = OrigParents.front(); - - auto *OrigParentCatch = - dyn_cast(OrigParent->getFirstNonPHI()); - if (!OrigParentCatch || getEndPadForCatch(OrigParentCatch) != UnwindDest) { - DEBUG_WITH_TYPE( - "winehprepare-coloring", - dbgs() << " removing unwind destination of original block \'" - << OrigBlock << "\'.\n"); - updateUnwindTerminator(OrigBlock); - } - } else if (auto *CleanupEnd = dyn_cast(EHPadInst)) { - // If the EH terminator unwinds to a cleanupendpad, that cleanupendpad - // must be ending a cleanuppad of either our clone parent or one - // one of the parents of the original funclet. - auto *CloneParentCP = - dyn_cast(CloneParent->getFirstNonPHI()); - auto *EndedCP = CleanupEnd->getCleanupPad(); - if (EndedCP == CloneParentCP) { - // If it is ending the cleanuppad of our cloned parent, then we - // want to remove the unwind destination of the EH terminator that - // we associated with the original funclet. - assert(isa(OrigBlock->getFirstNonPHI())); - DEBUG_WITH_TYPE( - "winehprepare-coloring", - dbgs() << " removing unwind destination of original block \'" - << OrigBlock->getName() << "\'.\n"); - updateUnwindTerminator(OrigBlock); - } else { - // If it isn't ending the cleanuppad of our clone parent, then we - // want to remove the unwind destination of the EH terminator that - // associated with our cloned funclet. - assert(isa(CloneBlock->getFirstNonPHI())); - DEBUG_WITH_TYPE( - "winehprepare-coloring", - dbgs() << " removing unwind destination of clone block \'" - << CloneBlock->getName() << "\'.\n"); - updateUnwindTerminator(CloneBlock); - } - } else { - // If the EH terminator unwinds to a catchpad, cleanuppad or - // terminatepad that EH pad must be a sibling of the funclet we're - // cloning. We'll clone it later and update one of the catchendpad - // instrunctions that unwinds to it at that time. - assert(isa(EHPadInst) || isa(EHPadInst) || - isa(EHPadInst)); - } -} - -// If the terminator is a catchpad, we must also clone the catchendpad to which -// it unwinds and add this to the clone parent's block list. The catchendpad -// unwinds to either its caller, a sibling EH pad, a cleanup end pad in its -// parent funclet or a catch end pad in its grandparent funclet (which must be -// coupled with the parent funclet). If it has no unwind destination -// (i.e. unwind to caller), there is nothing to be done. If the unwind -// destination is a sibling EH pad, we will update the terminators later (in -// resolveFuncletAncestryForPath). If it unwinds to a cleanup end pad or a -// catch end pad and this end pad corresponds to the clone parent, we will -// remove the unwind destination in the original catchendpad. If it unwinds to -// a cleanup end pad or a catch end pad that does not correspond to the clone -// parent, we will remove the unwind destination in the cloned catchendpad. -static void updateCatchTerminators( - Function &F, CatchPadInst *OrigCatch, CatchPadInst *CloneCatch, - std::vector &OrigParents, BasicBlock *CloneParent, - ValueToValueMapTy &VMap, - std::map> &BlockColors, - std::map> &FuncletBlocks) { - // If we're cloning a catch pad that unwinds to a catchendpad, we also - // need to clone the catchendpad. The coloring algorithm associates - // the catchendpad block with the funclet's parent, so we have some work - // to do here to figure out whether the original belongs to the clone - // parent or one of the original funclets other parents (it might have - // more than one at this point). In either case, we might also need to - // remove the unwind edge if the catchendpad doesn't unwind to a block - // in the right grandparent funclet. - Instruction *I = CloneCatch->getUnwindDest()->getFirstNonPHI(); - if (auto *CEP = dyn_cast(I)) { - assert(BlockColors[CEP->getParent()].size() == 1); - BasicBlock *CEPFunclet = *(BlockColors[CEP->getParent()].begin()); - BasicBlock *CEPCloneParent = nullptr; - CatchPadInst *PredCatch = nullptr; - if (CEPFunclet == CloneParent) { - // The catchendpad is in the clone parent, so we need to clone it - // and associate the clone with the original funclet's parent. If - // the original funclet had multiple parents, we'll add it to the - // first parent that isn't the clone parent. The logic in - // updateClonedEHPadUnwindToParent() will only remove the unwind edge - // if there is only one parent other than the clone parent, so we don't - // need to verify the ancestry. The catchendpad will eventually be - // cloned into the correct parent and all invalid unwind edges will be - // removed. - for (auto *Parent : OrigParents) { - if (Parent != CloneParent) { - CEPCloneParent = Parent; - break; - } - } - PredCatch = OrigCatch; - } else { - CEPCloneParent = CloneParent; - PredCatch = CloneCatch; - } - assert(CEPCloneParent && PredCatch); - DEBUG_WITH_TYPE("winehprepare-coloring", - dbgs() << " Cloning catchendpad \'" - << CEP->getParent()->getName() << "\' for funclet \'" - << CEPCloneParent->getName() << "\'.\n"); - BasicBlock *ClonedCEP = CloneBasicBlock( - CEP->getParent(), VMap, Twine(".from.", CEPCloneParent->getName())); - // Insert the clone immediately after the original to ensure determinism - // and to keep the same relative ordering of any funclet's blocks. - ClonedCEP->insertInto(&F, CEP->getParent()->getNextNode()); - PredCatch->setUnwindDest(ClonedCEP); - FuncletBlocks[CEPCloneParent].insert(ClonedCEP); - BlockColors[ClonedCEP].insert(CEPCloneParent); - DEBUG_WITH_TYPE("winehprepare-coloring", - dbgs() << " Assigning color \'" - << CEPCloneParent->getName() << "\' to block \'" - << ClonedCEP->getName() << "\'.\n"); - auto *ClonedCEPInst = cast(ClonedCEP->getTerminator()); - if (auto *Dest = ClonedCEPInst->getUnwindDest()) - updateClonedEHPadUnwindToParent(Dest, OrigCatch->getUnwindDest(), - CloneCatch->getUnwindDest(), OrigParents, - CloneParent); - } -} - -// While we are cloning a funclet because it has multiple parents, we will call -// this routine to update the terminators for the original and cloned copies -// of each basic block. All blocks in the funclet have been clone by this time. -// OrigBlock and CloneBlock will be identical except for their block label. -// -// If the terminator is a catchpad, we must also clone the catchendpad to which -// it unwinds and in most cases update either the original catchendpad or the -// clone. See the updateCatchTerminators() helper routine for details. -// -// If the terminator is a catchret its successor is a block in its parent -// funclet. If the instruction returns to a block in the parent for which the -// cloned funclet was created, the terminator in the original block must be -// replaced by an unreachable instruction. Otherwise the terminator in the -// clone block must be replaced by an unreachable instruction. -// -// If the terminator is a cleanupret or cleanupendpad it either unwinds to -// caller or unwinds to a sibling EH pad, a cleanup end pad in its parent -// funclet or a catch end pad in its grandparent funclet (which must be -// coupled with the parent funclet). If it unwinds to caller there is -// nothing to be done. If the unwind destination is a sibling EH pad, we will -// update the terminators later (in resolveFuncletAncestryForPath). If it -// unwinds to a cleanup end pad or a catch end pad and this end pad corresponds -// to the clone parent, we will replace the terminator in the original block -// with an unreachable instruction. If it unwinds to a cleanup end pad or a -// catch end pad that does not correspond to the clone parent, we will replace -// the terminator in the clone block with an unreachable instruction. -// -// If the terminator is an invoke instruction, we will handle it after all -// siblings of the current funclet have been cloned. -void WinEHPrepare::updateTerminatorsAfterFuncletClone( - Function &F, BasicBlock *OrigFunclet, BasicBlock *CloneFunclet, - BasicBlock *OrigBlock, BasicBlock *CloneBlock, BasicBlock *CloneParent, - ValueToValueMapTy &VMap, std::map &Orig2Clone) { - // If the cloned block doesn't have an exceptional terminator, there is - // nothing to be done here. - TerminatorInst *CloneTerminator = CloneBlock->getTerminator(); - if (!CloneTerminator->isExceptional()) - return; - - if (auto *CloneCatch = dyn_cast(CloneTerminator)) { - // A cloned catch pad has a lot of wrinkles, so we'll call a helper function - // to update this case. - auto *OrigCatch = cast(OrigBlock->getTerminator()); - updateCatchTerminators(F, OrigCatch, CloneCatch, - FuncletParents[OrigFunclet], CloneParent, VMap, - BlockColors, FuncletBlocks); - } else if (auto *CRI = dyn_cast(CloneTerminator)) { - if (FuncletBlocks[CloneParent].count(CRI->getSuccessor())) { - BasicBlock *OrigParent; - // The original funclet may have more than two parents, but that's OK. - // We just need to remap the original catchret to any of the parents. - // All of the parents should have an entry in the EstrangedBlocks map - // if any of them do. - if (FuncletParents[OrigFunclet].front() == CloneParent) - OrigParent = FuncletParents[OrigFunclet].back(); - else - OrigParent = FuncletParents[OrigFunclet].front(); - for (succ_iterator SI = succ_begin(OrigBlock), SE = succ_end(OrigBlock); - SI != SE; ++SI) - (*SI)->removePredecessor(OrigBlock); - BasicBlock *LostBlock = EstrangedBlocks[OrigParent][CRI->getSuccessor()]; - auto *OrigCatchRet = cast(OrigBlock->getTerminator()); - if (LostBlock) { - OrigCatchRet->setSuccessor(LostBlock); - } else { - OrigCatchRet->eraseFromParent(); - new UnreachableInst(OrigBlock->getContext(), OrigBlock); - } - } else { - for (succ_iterator SI = succ_begin(CloneBlock), SE = succ_end(CloneBlock); - SI != SE; ++SI) - (*SI)->removePredecessor(CloneBlock); - BasicBlock *LostBlock = EstrangedBlocks[CloneParent][CRI->getSuccessor()]; - if (LostBlock) { - CRI->setSuccessor(LostBlock); - } else { - CRI->eraseFromParent(); - new UnreachableInst(CloneBlock->getContext(), CloneBlock); - } - } - } else if (isa(CloneTerminator) || - isa(CloneTerminator)) { - BasicBlock *UnwindDest = nullptr; - - // A cleanup pad can unwind through either a cleanupret or a cleanupendpad - // but both are handled the same way. - if (auto *CRI = dyn_cast(CloneTerminator)) - UnwindDest = CRI->getUnwindDest(); - else if (auto *CEI = dyn_cast(CloneTerminator)) - UnwindDest = CEI->getUnwindDest(); - - // If the instruction has no local unwind destination, there is nothing - // to be done. - if (!UnwindDest) - return; - - // The unwind destination may be a sibling EH pad, a catchendpad in - // a grandparent funclet (ending a catchpad in the parent) or a cleanup - // cleanupendpad in the parent. Call a helper routine to diagnose this - // and remove either the clone or original terminator as needed. - updateClonedEHPadUnwindToParent(UnwindDest, OrigBlock, CloneBlock, - FuncletParents[OrigFunclet], CloneParent); - } -} - -// Clones all blocks used by the specified funclet to avoid the funclet having -// multiple parent funclets. All terminators in the parent that unwind to the -// original funclet are remapped to unwind to the clone. Any terminator in the -// original funclet which returned to this parent is converted to an unreachable -// instruction. Likewise, any terminator in the cloned funclet which returns to -// a parent funclet other than the specified parent is converted to an -// unreachable instruction. -BasicBlock *WinEHPrepare::cloneFuncletForParent(Function &F, - BasicBlock *FuncletEntry, - BasicBlock *Parent) { - std::set &BlocksInFunclet = FuncletBlocks[FuncletEntry]; - - DEBUG_WITH_TYPE("winehprepare-coloring", - dbgs() << "Cloning funclet \'" << FuncletEntry->getName() - << "\' for parent \'" << Parent->getName() << "\'.\n"); - - std::map Orig2Clone; - ValueToValueMapTy VMap; - for (BasicBlock *BB : BlocksInFunclet) { - // Create a new basic block and copy instructions into it. - BasicBlock *CBB = - CloneBasicBlock(BB, VMap, Twine(".from.", Parent->getName())); - - // Insert the clone immediately after the original to ensure determinism - // and to keep the same relative ordering of any funclet's blocks. - CBB->insertInto(&F, BB->getNextNode()); - - // Add basic block mapping. - VMap[BB] = CBB; - - // Record delta operations that we need to perform to our color mappings. - Orig2Clone[BB] = CBB; - } // end for (BasicBlock *BB : BlocksInFunclet) - - BasicBlock *ClonedFunclet = Orig2Clone[FuncletEntry]; - assert(ClonedFunclet); - - // Set the coloring for the blocks we just cloned. - std::set &ClonedBlocks = FuncletBlocks[ClonedFunclet]; - for (auto &BBMapping : Orig2Clone) { - BasicBlock *NewBlock = BBMapping.second; - ClonedBlocks.insert(NewBlock); - BlockColors[NewBlock].insert(ClonedFunclet); - - DEBUG_WITH_TYPE("winehprepare-coloring", - dbgs() << " Assigning color \'" << ClonedFunclet->getName() - << "\' to block \'" << NewBlock->getName() - << "\'.\n"); - - // Use the VMap to remap the instructions in this cloned block. - for (Instruction &I : *NewBlock) - RemapInstruction(&I, VMap, RF_IgnoreMissingEntries); - } - - // All the cloned blocks have to be colored in the loop above before we can - // update the terminators because doing so can require checking the color of - // other blocks in the cloned funclet. - for (auto &BBMapping : Orig2Clone) { - BasicBlock *OldBlock = BBMapping.first; - BasicBlock *NewBlock = BBMapping.second; - - // Update the terminator, if necessary, in both the original block and the - // cloned so that the original funclet never returns to a block in the - // clone parent and the clone funclet never returns to a block in any other - // of the original funclet's parents. - updateTerminatorsAfterFuncletClone(F, FuncletEntry, ClonedFunclet, OldBlock, - NewBlock, Parent, VMap, Orig2Clone); - - // Check to see if the cloned block successor has PHI nodes. If so, we need - // to add entries to the PHI nodes for the cloned block now. - for (BasicBlock *SuccBB : successors(NewBlock)) { - for (Instruction &SuccI : *SuccBB) { - auto *SuccPN = dyn_cast(&SuccI); - if (!SuccPN) - break; - - // Ok, we have a PHI node. Figure out what the incoming value was for - // the OldBlock. - int OldBlockIdx = SuccPN->getBasicBlockIndex(OldBlock); - if (OldBlockIdx == -1) - break; - Value *IV = SuccPN->getIncomingValue(OldBlockIdx); - - // Remap the value if necessary. - if (auto *Inst = dyn_cast(IV)) { - ValueToValueMapTy::iterator I = VMap.find(Inst); - if (I != VMap.end()) - IV = I->second; - } +void WinEHPrepare::colorFunclets(Function &F) { + BlockColors = colorEHFunclets(F); - SuccPN->addIncoming(IV, NewBlock); - } - } - } - - // Erase the clone's parent from the original funclet's parent list. - std::vector &Parents = FuncletParents[FuncletEntry]; - Parents.erase(std::remove(Parents.begin(), Parents.end(), Parent), - Parents.end()); - - // Store the cloned funclet's parent. - assert(std::find(FuncletParents[ClonedFunclet].begin(), - FuncletParents[ClonedFunclet].end(), - Parent) == std::end(FuncletParents[ClonedFunclet])); - FuncletParents[ClonedFunclet].push_back(Parent); - - // Copy any children of the original funclet to the clone. We'll either - // clone them too or make that path unreachable when we take the next step - // in resolveFuncletAncestryForPath(). - for (auto *Child : FuncletChildren[FuncletEntry]) { - assert(std::find(FuncletChildren[ClonedFunclet].begin(), - FuncletChildren[ClonedFunclet].end(), - Child) == std::end(FuncletChildren[ClonedFunclet])); - FuncletChildren[ClonedFunclet].push_back(Child); - assert(std::find(FuncletParents[Child].begin(), FuncletParents[Child].end(), - ClonedFunclet) == std::end(FuncletParents[Child])); - FuncletParents[Child].push_back(ClonedFunclet); - } - - // Find any blocks that unwound to the original funclet entry from the - // clone parent block and remap them to the clone. - for (auto *U : FuncletEntry->users()) { - auto *UT = dyn_cast(U); - if (!UT) - continue; - BasicBlock *UBB = UT->getParent(); - assert(BlockColors[UBB].size() == 1); - BasicBlock *UFunclet = *(BlockColors[UBB].begin()); - // Funclets shouldn't be able to loop back on themselves. - assert(UFunclet != FuncletEntry); - // If this instruction unwinds to the original funclet from the clone - // parent, remap the terminator so that it unwinds to the clone instead. - // We will perform a similar transformation for siblings after all - // the siblings have been cloned. - if (UFunclet == Parent) { - // We're about to break the path from this block to the uncloned funclet - // entry, so remove it as a predeccessor to clean up the PHIs. - FuncletEntry->removePredecessor(UBB); - TerminatorInst *Terminator = UBB->getTerminator(); - RemapInstruction(Terminator, VMap, RF_IgnoreMissingEntries); - } - } - - // This asserts a condition that is relied upon inside the loop below, - // namely that no predecessors of the original funclet entry block - // are also predecessors of the cloned funclet entry block. - assert(std::all_of(pred_begin(FuncletEntry), pred_end(FuncletEntry), - [&ClonedFunclet](BasicBlock *Pred) { - return std::find(pred_begin(ClonedFunclet), - pred_end(ClonedFunclet), - Pred) == pred_end(ClonedFunclet); - })); - - // Remove any invalid PHI node entries in the cloned funclet.cl - std::vector PHIsToErase; - for (Instruction &I : *ClonedFunclet) { - auto *PN = dyn_cast(&I); - if (!PN) - break; - - // Predecessors of the original funclet do not reach the cloned funclet, - // but the cloning process assumes they will. Remove them now. - for (auto *Pred : predecessors(FuncletEntry)) - PN->removeIncomingValue(Pred, false); - } - for (auto *PN : PHIsToErase) - PN->eraseFromParent(); - - // Replace the original funclet in the parent's children vector with the - // cloned funclet. - for (auto &It : FuncletChildren[Parent]) { - if (It == FuncletEntry) { - It = ClonedFunclet; - break; - } - } - - return ClonedFunclet; -} - -// Removes the unwind edge for any exceptional terminators within the specified -// parent funclet that previously unwound to the specified child funclet. -void WinEHPrepare::makeFuncletEdgeUnreachable(BasicBlock *Parent, - BasicBlock *Child) { - for (BasicBlock *BB : FuncletBlocks[Parent]) { - TerminatorInst *Terminator = BB->getTerminator(); - if (!Terminator->isExceptional()) - continue; - - // Look for terninators that unwind to the child funclet. - BasicBlock *UnwindDest = nullptr; - if (auto *I = dyn_cast(Terminator)) - UnwindDest = I->getUnwindDest(); - else if (auto *I = dyn_cast(Terminator)) - UnwindDest = I->getUnwindDest(); - else if (auto *I = dyn_cast(Terminator)) - UnwindDest = I->getUnwindDest(); - // cleanupendpad, catchret and cleanupret don't represent a parent-to-child - // funclet transition, so we don't need to consider them here. - - // If the child funclet is the unwind destination, replace the terminator - // with an unreachable instruction. - if (UnwindDest == Child) - removeUnwindEdge(BB); - } - // The specified parent is no longer a parent of the specified child. - std::vector &Children = FuncletChildren[Parent]; - Children.erase(std::remove(Children.begin(), Children.end(), Child), - Children.end()); -} - -// This routine is called after funclets with multiple parents are cloned for -// a specific parent. Here we look for children of the specified funclet that -// unwind to other children of that funclet and update the unwind destinations -// to ensure that each sibling is connected to the correct clone of the sibling -// to which it unwinds. -// -// If the terminator is an invoke instruction, it unwinds either to a child -// EH pad, a cleanup end pad in the current funclet, or a catch end pad in a -// parent funclet (which ends either the current catch pad or a sibling -// catch pad). If it unwinds to a child EH pad, the child will have multiple -// parents after this funclet is cloned and this case will be handled later in -// the resolveFuncletAncestryForPath processing. If it unwinds to a -// cleanup end pad in the current funclet, the instruction remapping during -// the cloning process should have already mapped the unwind destination to -// the cloned copy of the cleanup end pad. If it unwinds to a catch end pad -// there are two possibilities: either the catch end pad is the unwind -// destination for the catch pad we are currently cloning or it is the unwind -// destination for a sibling catch pad. If it it the unwind destination of the -// catch pad we are cloning, we need to update the cloned invoke instruction -// to unwind to the cloned catch end pad. Otherwise, we will handle this -// later (in resolveFuncletAncestryForPath). -static void updateSiblingToSiblingUnwind( - BasicBlock *CurFunclet, - std::map> &BlockColors, - std::map> &FuncletBlocks, - std::map> &FuncletParents, - std::map> &FuncletChildren, - std::map &Funclet2Orig) { - // Remap any bad sibling-to-sibling transitions for funclets that - // we just cloned. - for (BasicBlock *ChildFunclet : FuncletChildren[CurFunclet]) { - for (auto *BB : FuncletBlocks[ChildFunclet]) { - TerminatorInst *Terminator = BB->getTerminator(); - if (!Terminator->isExceptional()) - continue; - - // See if this terminator has an unwind destination. - // Note that catchendpads are handled when the associated catchpad - // is cloned. They don't fit the pattern we're looking for here. - BasicBlock *UnwindDest = nullptr; - if (auto *I = dyn_cast(Terminator)) { - UnwindDest = I->getUnwindDest(); - // The catchendpad is not a sibling destination. This case should - // have been handled in cloneFuncletForParent(). - if (isa(Terminator)) { - assert(BlockColors[UnwindDest].size() == 1 && - "Cloned catchpad unwinds to an pad with multiple parents."); - assert(FuncletParents[UnwindDest].front() == CurFunclet && - "Cloned catchpad unwinds to the wrong parent."); - continue; - } - } else { - if (auto *I = dyn_cast(Terminator)) - UnwindDest = I->getUnwindDest(); - else if (auto *I = dyn_cast(Terminator)) - UnwindDest = I->getUnwindDest(); - - // If the cleanup unwinds to caller, there is nothing to be done. - if (!UnwindDest) - continue; - } - - // If the destination is not a cleanup pad, catch pad or terminate pad - // we don't need to handle it here. - Instruction *EHPad = UnwindDest->getFirstNonPHI(); - if (!isa(EHPad) && !isa(EHPad) && - !isa(EHPad)) - continue; - - // If it is one of these, then it is either a sibling of the current - // child funclet or a clone of one of those siblings. - // If it is a sibling, no action is needed. - if (FuncletParents[UnwindDest].size() == 1 && - FuncletParents[UnwindDest].front() == CurFunclet) - continue; - - // If the unwind destination is a clone of a sibling, we need to figure - // out which sibling it is a clone of and use that sibling as the - // unwind destination. - BasicBlock *DestOrig = Funclet2Orig[UnwindDest]; - BasicBlock *TargetSibling = nullptr; - for (auto &Mapping : Funclet2Orig) { - if (Mapping.second != DestOrig) - continue; - BasicBlock *MappedFunclet = Mapping.first; - if (FuncletParents[MappedFunclet].size() == 1 && - FuncletParents[MappedFunclet].front() == CurFunclet) { - TargetSibling = MappedFunclet; - } - } - // If we didn't find the sibling we were looking for then the - // unwind destination is not a clone of one of child's siblings. - // That's unexpected. - assert(TargetSibling && "Funclet unwinds to unexpected destination."); - - // Update the terminator instruction to unwind to the correct sibling. - if (auto *I = dyn_cast(Terminator)) - I->setUnwindDest(TargetSibling); - else if (auto *I = dyn_cast(Terminator)) - I->setUnwindDest(TargetSibling); - else if (auto *I = dyn_cast(Terminator)) - I->setUnwindDest(TargetSibling); - } - } - - // Invoke remapping can't be done correctly until after all of their - // other sibling-to-sibling unwinds have been remapped. - for (BasicBlock *ChildFunclet : FuncletChildren[CurFunclet]) { - bool NeedOrigInvokeRemapping = false; - for (auto *BB : FuncletBlocks[ChildFunclet]) { - TerminatorInst *Terminator = BB->getTerminator(); - auto *II = dyn_cast(Terminator); - if (!II) - continue; - - BasicBlock *UnwindDest = II->getUnwindDest(); - assert(UnwindDest && "Invoke unwinds to a null destination."); - assert(UnwindDest->isEHPad() && "Invoke does not unwind to an EH pad."); - auto *EHPadInst = UnwindDest->getFirstNonPHI(); - if (isa(EHPadInst)) { - // An invoke that unwinds to a cleanup end pad must be in a cleanup pad. - assert(isa(ChildFunclet->getFirstNonPHI()) && - "Unwinding to cleanup end pad from a non cleanup pad funclet."); - // The funclet cloning should have remapped the destination to the cloned - // cleanup end pad. - assert(FuncletBlocks[ChildFunclet].count(UnwindDest) && - "Unwind destination for invoke was not updated during cloning."); - } else if (isa(EHPadInst)) { - // If the invoke unwind destination is the unwind destination for - // the current child catch pad funclet, there is nothing to be done. - BasicBlock *OrigFunclet = Funclet2Orig[ChildFunclet]; - auto *CurCatch = cast(ChildFunclet->getFirstNonPHI()); - auto *OrigCatch = cast(OrigFunclet->getFirstNonPHI()); - if (OrigCatch->getUnwindDest() == UnwindDest) { - // If the invoke unwinds to a catch end pad that is the unwind - // destination for the original catch pad, the cloned invoke should - // unwind to the cloned catch end pad. - II->setUnwindDest(CurCatch->getUnwindDest()); - } else if (CurCatch->getUnwindDest() == UnwindDest) { - // If the invoke unwinds to a catch end pad that is the unwind - // destination for the clone catch pad, the original invoke should - // unwind to the unwind destination of the original catch pad. - // This happens when the catch end pad is matched to the clone - // parent when the catchpad instruction is cloned and the original - // invoke instruction unwinds to the original catch end pad (which - // is now the unwind destination of the cloned catch pad). - NeedOrigInvokeRemapping = true; - } else { - // Otherwise, the invoke unwinds to a catch end pad that is the unwind - // destination another catch pad in the unwind chain from either the - // current catch pad or one of its clones. If it is already the - // catch end pad at the end unwind chain from the current catch pad, - // we'll need to check the invoke instructions in the original funclet - // later. Otherwise, we need to remap this invoke now. - assert((getEndPadForCatch(OrigCatch) == UnwindDest || - getEndPadForCatch(CurCatch) == UnwindDest) && - "Invoke within catch pad unwinds to an invalid catch end pad."); - BasicBlock *CurCatchEnd = getEndPadForCatch(CurCatch); - if (CurCatchEnd == UnwindDest) - NeedOrigInvokeRemapping = true; - else - II->setUnwindDest(CurCatchEnd); - } - } - } - if (NeedOrigInvokeRemapping) { - // To properly remap invoke instructions that unwind to catch end pads - // that are not the unwind destination of the catch pad funclet in which - // the invoke appears, we must also look at the uncloned invoke in the - // original funclet. If we saw an invoke that was already properly - // unwinding to a sibling's catch end pad, we need to check the invokes - // in the original funclet. - BasicBlock *OrigFunclet = Funclet2Orig[ChildFunclet]; - for (auto *BB : FuncletBlocks[OrigFunclet]) { - auto *II = dyn_cast(BB->getTerminator()); - if (!II) - continue; - - BasicBlock *UnwindDest = II->getUnwindDest(); - assert(UnwindDest && "Invoke unwinds to a null destination."); - assert(UnwindDest->isEHPad() && "Invoke does not unwind to an EH pad."); - auto *CEP = dyn_cast(UnwindDest->getFirstNonPHI()); - if (!CEP) - continue; - - // If the invoke unwind destination is the unwind destination for - // the original catch pad funclet, there is nothing to be done. - auto *OrigCatch = cast(OrigFunclet->getFirstNonPHI()); - - // If the invoke unwinds to a catch end pad that is neither the unwind - // destination of OrigCatch or the destination another catch pad in the - // unwind chain from current catch pad, we need to remap the invoke. - BasicBlock *OrigCatchEnd = getEndPadForCatch(OrigCatch); - if (OrigCatchEnd != UnwindDest) - II->setUnwindDest(OrigCatchEnd); - } - } - } -} - -void WinEHPrepare::resolveFuncletAncestry( - Function &F, SmallVectorImpl &EntryBlocks) { - // Most of the time this will be unnecessary. If the conditions arise that - // require this work, this flag will be set. - if (!FuncletCloningRequired) - return; - - // Funclet2Orig is used to map any cloned funclets back to the original - // funclet from which they were cloned. The map is seeded with the - // original funclets mapping to themselves. - std::map Funclet2Orig; - for (auto *Funclet : EntryBlocks) - Funclet2Orig[Funclet] = Funclet; - - // Start with the entry funclet and walk the funclet parent-child tree. - SmallVector FuncletPath; - FuncletPath.push_back(&(F.getEntryBlock())); - resolveFuncletAncestryForPath(F, FuncletPath, Funclet2Orig); -} - -// Walks the funclet control flow, cloning any funclets that have more than one -// parent funclet and breaking any cyclic unwind chains so that the path becomes -// unreachable at the point where a funclet would have unwound to a funclet that -// was already in the chain. -void WinEHPrepare::resolveFuncletAncestryForPath( - Function &F, SmallVectorImpl &FuncletPath, - std::map &Funclet2Orig) { - bool ClonedAnyChildren = false; - BasicBlock *CurFunclet = FuncletPath.back(); - // Copy the children vector because we might changing it. - std::vector Children(FuncletChildren[CurFunclet]); - for (BasicBlock *ChildFunclet : Children) { - // Don't allow the funclet chain to unwind back on itself. - // If this funclet is already in the current funclet chain, make the - // path to it through the current funclet unreachable. - bool IsCyclic = false; - BasicBlock *ChildIdentity = Funclet2Orig[ChildFunclet]; - for (BasicBlock *Ancestor : FuncletPath) { - BasicBlock *AncestorIdentity = Funclet2Orig[Ancestor]; - if (AncestorIdentity == ChildIdentity) { - IsCyclic = true; - break; - } - } - // If the unwind chain wraps back on itself, break the chain. - if (IsCyclic) { - makeFuncletEdgeUnreachable(CurFunclet, ChildFunclet); - continue; - } - // If this child funclet has other parents, clone the entire funclet. - if (FuncletParents[ChildFunclet].size() > 1) { - ChildFunclet = cloneFuncletForParent(F, ChildFunclet, CurFunclet); - Funclet2Orig[ChildFunclet] = ChildIdentity; - ClonedAnyChildren = true; - } - FuncletPath.push_back(ChildFunclet); - resolveFuncletAncestryForPath(F, FuncletPath, Funclet2Orig); - FuncletPath.pop_back(); - } - // If we didn't clone any children, we can return now. - if (!ClonedAnyChildren) - return; - - updateSiblingToSiblingUnwind(CurFunclet, BlockColors, FuncletBlocks, - FuncletParents, FuncletChildren, Funclet2Orig); -} - -void WinEHPrepare::colorFunclets(Function &F, - SmallVectorImpl &EntryBlocks) { - ::colorFunclets(F, EntryBlocks, BlockColors, FuncletBlocks); - - // The processing above actually accumulated the parent set for this - // funclet into the color set for its entry; use the parent set to - // populate the children map, and reset the color set to include just - // the funclet itself (no instruction can target a funclet entry except on - // that transitions to the child funclet). - for (BasicBlock *FuncletEntry : EntryBlocks) { - SetVector &ColorMapItem = BlockColors[FuncletEntry]; - // It will be rare for funclets to have multiple parents, but if any - // do we need to clone the funclet later to address that. Here we - // set a flag indicating that this case has arisen so that we don't - // have to do a lot of checking later to handle the more common case. - if (ColorMapItem.size() > 1) - FuncletCloningRequired = true; - for (BasicBlock *Parent : ColorMapItem) { - assert(std::find(FuncletChildren[Parent].begin(), - FuncletChildren[Parent].end(), - FuncletEntry) == std::end(FuncletChildren[Parent])); - FuncletChildren[Parent].push_back(FuncletEntry); - assert(std::find(FuncletParents[FuncletEntry].begin(), - FuncletParents[FuncletEntry].end(), - Parent) == std::end(FuncletParents[FuncletEntry])); - FuncletParents[FuncletEntry].push_back(Parent); - } - ColorMapItem.clear(); - ColorMapItem.insert(FuncletEntry); + // Invert the map from BB to colors to color to BBs. + for (BasicBlock &BB : F) { + ColorVector &Colors = BlockColors[&BB]; + for (BasicBlock *Color : Colors) + FuncletBlocks[Color].push_back(&BB); } } void llvm::calculateCatchReturnSuccessorColors(const Function *Fn, WinEHFuncInfo &FuncInfo) { - SmallVector EntryBlocks; - // colorFunclets needs the set of EntryBlocks, get them using - // findFuncletEntryPoints. - findFuncletEntryPoints(const_cast(*Fn), EntryBlocks); - - std::map> BlockColors; - std::map> FuncletBlocks; - // Figure out which basic blocks belong to which funclets. - colorFunclets(const_cast(*Fn), EntryBlocks, BlockColors, - FuncletBlocks); - - // The static colorFunclets routine assigns multiple colors to funclet entries - // because that information is needed to calculate funclets' parent-child - // relationship, but we don't need those relationship here and ultimately the - // entry blocks should have the color of the funclet they begin. - for (BasicBlock *FuncletEntry : EntryBlocks) { - BlockColors[FuncletEntry].clear(); - BlockColors[FuncletEntry].insert(FuncletEntry); - } - - // We need to find the catchret successors. To do this, we must first find - // all the catchpad funclets. - for (auto &Funclet : FuncletBlocks) { - // Figure out what kind of funclet we are looking at; We only care about - // catchpads. - BasicBlock *FuncletPadBB = Funclet.first; - Instruction *FirstNonPHI = FuncletPadBB->getFirstNonPHI(); - auto *CatchPad = dyn_cast(FirstNonPHI); - if (!CatchPad) + for (const BasicBlock &BB : *Fn) { + const auto *CatchRet = dyn_cast(BB.getTerminator()); + if (!CatchRet) continue; - - // The users of a catchpad are always catchrets. - for (User *Exit : CatchPad->users()) { - auto *CatchReturn = dyn_cast(Exit); - if (!CatchReturn) - continue; - BasicBlock *CatchRetSuccessor = CatchReturn->getSuccessor(); - SetVector &SuccessorColors = BlockColors[CatchRetSuccessor]; - assert(SuccessorColors.size() == 1 && "Expected BB to be monochrome!"); - BasicBlock *Color = *SuccessorColors.begin(); - // Record the catchret successor's funclet membership. - FuncInfo.CatchRetSuccessorColorMap[CatchReturn] = Color; - } + // A 'catchret' returns to the outer scope's color. + Value *OuterScope = CatchRet->getParentPad(); + const BasicBlock *Color; + if (isa(OuterScope)) + Color = &Fn->getEntryBlock(); + else + Color = cast(OuterScope)->getParent(); + // Record the catchret successor's funclet membership. + FuncInfo.CatchRetSuccessorColorMap[CatchRet] = Color; } } @@ -1584,70 +620,23 @@ } } -void WinEHPrepare::cloneCommonBlocks( - Function &F, SmallVectorImpl &EntryBlocks) { +void WinEHPrepare::cloneCommonBlocks(Function &F) { // We need to clone all blocks which belong to multiple funclets. Values are // remapped throughout the funclet to propogate both the new instructions // *and* the new basic blocks themselves. - for (BasicBlock *FuncletPadBB : EntryBlocks) { - std::set &BlocksInFunclet = FuncletBlocks[FuncletPadBB]; + for (auto &Funclets : FuncletBlocks) { + BasicBlock *FuncletPadBB = Funclets.first; + std::vector &BlocksInFunclet = Funclets.second; - std::map Orig2Clone; + std::vector> Orig2Clone; ValueToValueMapTy VMap; - for (auto BlockIt = BlocksInFunclet.begin(), - BlockEnd = BlocksInFunclet.end(); - BlockIt != BlockEnd;) { - // Increment the iterator inside the loop because we might be removing - // blocks from the set. - BasicBlock *BB = *BlockIt++; - SetVector &ColorsForBB = BlockColors[BB]; + for (BasicBlock *BB : BlocksInFunclet) { + ColorVector &ColorsForBB = BlockColors[BB]; // We don't need to do anything if the block is monochromatic. size_t NumColorsForBB = ColorsForBB.size(); if (NumColorsForBB == 1) continue; - // If this block is a catchendpad, it shouldn't be cloned. - // We will only see a catchendpad with multiple colors in the case where - // some funclet has multiple parents. In that case, the color will be - // resolved during the resolveFuncletAncestry processing. - // For now, find the catchpad that unwinds to this block and assign - // that catchpad's first parent to be the color for this block. - if (isa(BB->getFirstNonPHI())) { - assert( - FuncletCloningRequired && - "Found multi-colored catchendpad with no multi-parent funclets."); - BasicBlock *CatchParent = nullptr; - // There can only be one catchpad predecessor for a catchendpad. - for (BasicBlock *PredBB : predecessors(BB)) { - if (isa(PredBB->getTerminator())) { - CatchParent = PredBB; - break; - } - } - // There must be one catchpad predecessor for a catchendpad. - assert(CatchParent && "No catchpad found for catchendpad."); - - // If the catchpad has multiple parents, we'll clone the catchendpad - // when we clone the catchpad funclet and insert it into the correct - // funclet. For now, we just select the first parent of the catchpad - // and give the catchendpad that color. - BasicBlock *CorrectColor = FuncletParents[CatchParent].front(); - assert(FuncletBlocks[CorrectColor].count(BB)); - assert(BlockColors[BB].count(CorrectColor)); - - // Remove this block from the FuncletBlocks set of any funclet that - // isn't the funclet whose color we just selected. - for (BasicBlock *ContainingFunclet : BlockColors[BB]) - if (ContainingFunclet != CorrectColor) - FuncletBlocks[ContainingFunclet].erase(BB); - BlockColors[BB].remove_if([&](BasicBlock *ContainingFunclet) { - return ContainingFunclet != CorrectColor; - }); - // This should leave just one color for BB. - assert(BlockColors[BB].size() == 1); - continue; - } - DEBUG_WITH_TYPE("winehprepare-coloring", dbgs() << " Cloning block \'" << BB->getName() << "\' for funclet \'" << FuncletPadBB->getName() @@ -1664,7 +653,7 @@ VMap[BB] = CBB; // Record delta operations that we need to perform to our color mappings. - Orig2Clone[BB] = CBB; + Orig2Clone.emplace_back(BB, CBB); } // If nothing was cloned, we're done cloning in this funclet. @@ -1677,55 +666,28 @@ BasicBlock *OldBlock = BBMapping.first; BasicBlock *NewBlock = BBMapping.second; - BlocksInFunclet.insert(NewBlock); - BlockColors[NewBlock].insert(FuncletPadBB); + BlocksInFunclet.push_back(NewBlock); + ColorVector &NewColors = BlockColors[NewBlock]; + assert(NewColors.empty() && "A new block should only have one color!"); + NewColors.push_back(FuncletPadBB); DEBUG_WITH_TYPE("winehprepare-coloring", dbgs() << " Assigned color \'" << FuncletPadBB->getName() << "\' to block \'" << NewBlock->getName() << "\'.\n"); - BlocksInFunclet.erase(OldBlock); - BlockColors[OldBlock].remove(FuncletPadBB); + BlocksInFunclet.erase( + std::remove(BlocksInFunclet.begin(), BlocksInFunclet.end(), OldBlock), + BlocksInFunclet.end()); + ColorVector &OldColors = BlockColors[OldBlock]; + OldColors.erase( + std::remove(OldColors.begin(), OldColors.end(), FuncletPadBB), + OldColors.end()); DEBUG_WITH_TYPE("winehprepare-coloring", dbgs() << " Removed color \'" << FuncletPadBB->getName() << "\' from block \'" << OldBlock->getName() << "\'.\n"); - - // If we are cloning a funclet that might share a child funclet with - // another funclet, look to see if the cloned block is reached from a - // catchret instruction. If so, save this association so we can retrieve - // the possibly orphaned clone when we clone the child funclet. - if (FuncletCloningRequired) { - for (auto *Pred : predecessors(OldBlock)) { - auto *Terminator = Pred->getTerminator(); - if (!isa(Terminator)) - continue; - // If this block is reached from a catchret instruction in a funclet - // that has multiple parents, it will have a color for each of those - // parents. We just removed the color of one of the parents, but - // the cloned block will be unreachable until we clone the child - // funclet that contains the catchret instruction. In that case we - // need to create a mapping that will let us find the cloned block - // later and associate it with the cloned child funclet. - bool BlockWillBeEstranged = false; - for (auto *Color : BlockColors[Pred]) { - if (FuncletParents[Color].size() > 1) { - BlockWillBeEstranged = true; - break; // Breaks out of the color loop - } - } - if (BlockWillBeEstranged) { - EstrangedBlocks[FuncletPadBB][OldBlock] = NewBlock; - DEBUG_WITH_TYPE("winehprepare-coloring", - dbgs() << " Saved mapping of estranged block \'" - << NewBlock->getName() << "\' for \'" - << FuncletPadBB->getName() << "\'.\n"); - break; // Breaks out of the predecessor loop - } - } - } } // Loop over all of the instructions in this funclet, fixing up operand @@ -1736,6 +698,40 @@ RemapInstruction(&I, VMap, RF_IgnoreMissingEntries | RF_NoModuleLevelChanges); + auto UpdatePHIOnClonedBlock = [&](PHINode *PN, bool IsForOldBlock) { + unsigned NumPreds = PN->getNumIncomingValues(); + for (unsigned PredIdx = 0, PredEnd = NumPreds; PredIdx != PredEnd; + ++PredIdx) { + BasicBlock *IncomingBlock = PN->getIncomingBlock(PredIdx); + ColorVector &IncomingColors = BlockColors[IncomingBlock]; + bool BlockInFunclet = IncomingColors.size() == 1 && + IncomingColors.front() == FuncletPadBB; + if (IsForOldBlock != BlockInFunclet) + continue; + PN->removeIncomingValue(IncomingBlock, /*DeletePHIIfEmpty=*/false); + // Revisit the next entry. + --PredIdx; + --PredEnd; + } + }; + + for (auto &BBMapping : Orig2Clone) { + BasicBlock *OldBlock = BBMapping.first; + BasicBlock *NewBlock = BBMapping.second; + for (Instruction &OldI : *OldBlock) { + auto *OldPN = dyn_cast(&OldI); + if (!OldPN) + break; + UpdatePHIOnClonedBlock(OldPN, /*IsForOldBlock=*/true); + } + for (Instruction &NewI : *NewBlock) { + auto *NewPN = dyn_cast(&NewI); + if (!NewPN) + break; + UpdatePHIOnClonedBlock(NewPN, /*IsForOldBlock=*/false); + } + } + // Check to see if SuccBB has PHI nodes. If so, we need to add entries to // the PHI nodes for NewBB now. for (auto &BBMapping : Orig2Clone) { @@ -1783,7 +779,7 @@ for (Use &U : OldI->uses()) { Instruction *UserI = cast(U.getUser()); BasicBlock *UserBB = UserI->getParent(); - SetVector &ColorsForUserBB = BlockColors[UserBB]; + ColorVector &ColorsForUserBB = BlockColors[UserBB]; assert(!ColorsForUserBB.empty()); if (ColorsForUserBB.size() > 1 || *ColorsForUserBB.begin() != FuncletPadBB) @@ -1813,10 +809,10 @@ // Remove implausible terminators and replace them with UnreachableInst. for (auto &Funclet : FuncletBlocks) { BasicBlock *FuncletPadBB = Funclet.first; - std::set &BlocksInFunclet = Funclet.second; - Instruction *FirstNonPHI = FuncletPadBB->getFirstNonPHI(); - auto *CatchPad = dyn_cast(FirstNonPHI); - auto *CleanupPad = dyn_cast(FirstNonPHI); + std::vector &BlocksInFunclet = Funclet.second; + Instruction *FuncletPadInst = FuncletPadBB->getFirstNonPHI(); + auto *CatchPad = dyn_cast(FuncletPadInst); + auto *CleanupPad = dyn_cast(FuncletPadInst); for (BasicBlock *BB : BlocksInFunclet) { TerminatorInst *TI = BB->getTerminator(); @@ -1830,34 +826,22 @@ bool IsUnreachableCleanupret = false; if (auto *CRI = dyn_cast(TI)) IsUnreachableCleanupret = CRI->getCleanupPad() != CleanupPad; - // The token consumed by a CleanupEndPadInst must match the funclet token. - bool IsUnreachableCleanupendpad = false; - if (auto *CEPI = dyn_cast(TI)) - IsUnreachableCleanupendpad = CEPI->getCleanupPad() != CleanupPad; if (IsUnreachableRet || IsUnreachableCatchret || - IsUnreachableCleanupret || IsUnreachableCleanupendpad) { + IsUnreachableCleanupret) { // Loop through all of our successors and make sure they know that one // of their predecessors is going away. for (BasicBlock *SuccBB : TI->successors()) SuccBB->removePredecessor(BB); - if (IsUnreachableCleanupendpad) { - // We can't simply replace a cleanupendpad with unreachable, because - // its predecessor edges are EH edges and unreachable is not an EH - // pad. Change all predecessors to the "unwind to caller" form. - for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB); - PI != PE;) { - BasicBlock *Pred = *PI++; - removeUnwindEdge(Pred); - } - } - new UnreachableInst(BB->getContext(), TI); TI->eraseFromParent(); + } else if (isa(TI)) { + // Invokes within a cleanuppad for the MSVC++ personality never + // transfer control to their unwind edge: the personality will + // terminate the program. + if (Personality == EHPersonality::MSVC_CXX && CleanupPad) + removeUnwindEdge(BB); } - // FIXME: Check for invokes/cleanuprets/cleanupendpads which unwind to - // implausible catchendpads (i.e. catchendpad not in immediate parent - // funclet). } } } @@ -1886,27 +870,31 @@ report_fatal_error("Uncolored BB!"); if (NumColors > 1) report_fatal_error("Multicolor BB!"); - bool EHPadHasPHI = BB.isEHPad() && isa(BB.begin()); - assert(!EHPadHasPHI && "EH Pad still has a PHI!"); - if (EHPadHasPHI) - report_fatal_error("EH Pad still has a PHI!"); + if (!DisableDemotion) { + bool EHPadHasPHI = BB.isEHPad() && isa(BB.begin()); + assert(!EHPadHasPHI && "EH Pad still has a PHI!"); + if (EHPadHasPHI) + report_fatal_error("EH Pad still has a PHI!"); + } } } -bool WinEHPrepare::prepareExplicitEH( - Function &F, SmallVectorImpl &EntryBlocks) { +bool WinEHPrepare::prepareExplicitEH(Function &F) { + // Remove unreachable blocks. It is not valuable to assign them a color and + // their existence can trick us into thinking values are alive when they are + // not. + removeUnreachableBlocks(F); + replaceTerminatePadWithCleanup(F); // Determine which blocks are reachable from which funclet entries. - colorFunclets(F, EntryBlocks); + colorFunclets(F); + + cloneCommonBlocks(F); if (!DisableDemotion) demotePHIsOnFunclets(F); - cloneCommonBlocks(F, EntryBlocks); - - resolveFuncletAncestry(F, EntryBlocks); - if (!DisableCleanups) { removeImplausibleTerminators(F); @@ -1917,10 +905,6 @@ BlockColors.clear(); FuncletBlocks.clear(); - FuncletChildren.clear(); - FuncletParents.clear(); - EstrangedBlocks.clear(); - FuncletCloningRequired = false; return true; } @@ -1930,9 +914,11 @@ AllocaInst *WinEHPrepare::insertPHILoads(PHINode *PN, Function &F) { BasicBlock *PHIBlock = PN->getParent(); AllocaInst *SpillSlot = nullptr; + Instruction *EHPad = PHIBlock->getFirstNonPHI(); - if (isa(PHIBlock->getFirstNonPHI())) { - // Insert a load in place of the PHI and replace all uses. + if (!isa(EHPad)) { + // If the EHPad isn't a terminator, then we can insert a load in this block + // that will dominate all uses. SpillSlot = new AllocaInst(PN->getType(), nullptr, Twine(PN->getName(), ".wineh.spillslot"), &F.getEntryBlock().front()); @@ -1942,16 +928,16 @@ return SpillSlot; } + // Otherwise, we have a PHI on a terminator EHPad, and we give up and insert + // loads of the slot before every use. DenseMap Loads; for (Value::use_iterator UI = PN->use_begin(), UE = PN->use_end(); UI != UE;) { Use &U = *UI++; auto *UsingInst = cast(U.getUser()); - BasicBlock *UsingBB = UsingInst->getParent(); - if (UsingBB->isEHPad()) { + if (isa(UsingInst) && UsingInst->getParent()->isEHPad()) { // Use is on an EH pad phi. Leave it alone; we'll insert loads and // stores for it separately. - assert(isa(UsingInst)); continue; } replaceUseWithLoad(PN, U, SpillSlot, Loads, F); @@ -2005,7 +991,7 @@ SmallVectorImpl> &Worklist) { if (PredBlock->isEHPad() && - !isa(PredBlock->getFirstNonPHI())) { + isa(PredBlock->getFirstNonPHI())) { // Pred is unsplittable, so we need to queue it on the worklist. Worklist.push_back({PredBlock, PredVal}); return; @@ -2065,10 +1051,10 @@ Goto->setSuccessor(0, PHIBlock); CatchRet->setSuccessor(NewBlock); // Update the color mapping for the newly split edge. - SetVector &ColorsForPHIBlock = BlockColors[PHIBlock]; + ColorVector &ColorsForPHIBlock = BlockColors[PHIBlock]; BlockColors[NewBlock] = ColorsForPHIBlock; for (BasicBlock *FuncletPad : ColorsForPHIBlock) - FuncletBlocks[FuncletPad].insert(NewBlock); + FuncletBlocks[FuncletPad].push_back(NewBlock); // Treat the new block as incoming for load insertion. IncomingBlock = NewBlock; } @@ -2087,11 +1073,10 @@ } } -void WinEHFuncInfo::addIPToStateRange(const BasicBlock *PadBB, +void WinEHFuncInfo::addIPToStateRange(const InvokeInst *II, MCSymbol *InvokeBegin, MCSymbol *InvokeEnd) { - assert(PadBB->isEHPad() && EHPadStateMap.count(PadBB->getFirstNonPHI()) && - "should get EH pad BB with precomputed state"); - InvokeToStateMap[InvokeBegin] = - std::make_pair(EHPadStateMap[PadBB->getFirstNonPHI()], InvokeEnd); + assert(InvokeStateMap.count(II) && + "should get invoke with precomputed state"); + LabelToStateMap[InvokeBegin] = std::make_pair(InvokeStateMap[II], InvokeEnd); } Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -2890,19 +2890,36 @@ writeOperand(LPI->getClause(i), true); } - } else if (const auto *CPI = dyn_cast(&I)) { + } else if (const auto *CatchSwitch = dyn_cast(&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(&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(&I)) { + Out << " within "; + writeOperand(TPI->getParentPad(), /*PrintType=*/false); Out << " ["; for (unsigned Op = 0, NumOps = TPI->getNumArgOperands(); Op < NumOps; ++Op) { @@ -2915,44 +2932,21 @@ writeOperand(TPI->getUnwindDest(), /*PrintType=*/true); else Out << "to caller"; - } else if (const auto *CPI = dyn_cast(&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(I) && !Operand) { Out << " void"; } else if (const auto *CRI = dyn_cast(&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(&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(&I)) { - Out << " unwind "; - if (CEPI->hasUnwindDest()) - writeOperand(CEPI->getUnwindDest(), /*PrintType=*/true); - else - Out << "to caller"; - } else if (const auto *CEPI = dyn_cast(&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(&I)) { Index: lib/IR/Dominators.cpp =================================================================== --- lib/IR/Dominators.cpp +++ lib/IR/Dominators.cpp @@ -91,11 +91,11 @@ 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(Def) || isa(Def) || isa(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(Def) || isa(User)) return dominates(Def, UseBB); if (DefBB != UseBB) @@ -126,18 +126,13 @@ 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(Def)) { BasicBlock *NormalDest = II->getNormalDest(); BasicBlockEdge E(DefBB, NormalDest); return dominates(E, UseBB); } - if (const auto *CPI = dyn_cast(Def)) { - BasicBlock *NormalDest = CPI->getNormalDest(); - BasicBlockEdge E(DefBB, NormalDest); - return dominates(E, UseBB); - } return dominates(DefBB, UseBB); } @@ -239,8 +234,8 @@ 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 @@ BasicBlockEdge E(DefBB, NormalDest); return dominates(E, U); } - if (const auto *CPI = dyn_cast(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. Index: lib/IR/Instruction.cpp =================================================================== --- lib/IR/Instruction.cpp +++ lib/IR/Instruction.cpp @@ -202,11 +202,10 @@ 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 @@ return !CI->doesNotThrow(); if (const auto *CRI = dyn_cast(this)) return CRI->unwindsToCaller(); - if (const auto *CEPI = dyn_cast(this)) - return CEPI->unwindsToCaller(); - if (const auto *CEPI = dyn_cast(this)) - return CEPI->unwindsToCaller(); + if (const auto *CatchSwitch = dyn_cast(this)) + return CatchSwitch->unwindsToCaller(); if (const auto *TPI = dyn_cast(this)) return TPI->unwindsToCaller(); return isa(this); Index: lib/IR/Instructions.cpp =================================================================== --- lib/IR/Instructions.cpp +++ lib/IR/Instructions.cpp @@ -764,61 +764,6 @@ } //===----------------------------------------------------------------------===// -// CleanupEndPadInst Implementation -//===----------------------------------------------------------------------===// - -CleanupEndPadInst::CleanupEndPadInst(const CleanupEndPadInst &CEPI) - : TerminatorInst(CEPI.getType(), Instruction::CleanupEndPad, - OperandTraits::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::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::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 @@ 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::op_end(this) - Values, @@ -852,9 +796,8 @@ 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::op_end(this) - Values, @@ -875,58 +818,9 @@ } //===----------------------------------------------------------------------===// -// CatchEndPadInst Implementation -//===----------------------------------------------------------------------===// - -CatchEndPadInst::CatchEndPadInst(const CatchEndPadInst &CRI) - : TerminatorInst(CRI.getType(), Instruction::CatchEndPad, - OperandTraits::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::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::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 @@ 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::op_begin(this), 2, @@ -946,7 +840,7 @@ 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::op_begin(this), 2, @@ -967,64 +861,136 @@ } //===----------------------------------------------------------------------===// -// CatchPadInst Implementation +// CatchSwitchInst Implementation //===----------------------------------------------------------------------===// -void CatchPadInst::init(BasicBlock *IfNormal, BasicBlock *IfException, - ArrayRef 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 *OuterScope, BasicBlock *UnwindDest, + unsigned NumReservedValues, + const Twine &NameStr, + Instruction *InsertBefore) + : TerminatorInst(OuterScope->getType(), Instruction::CatchSwitch, nullptr, + 0, InsertBefore) { + if (UnwindDest) + ++NumReservedValues; + init(OuterScope, UnwindDest, NumReservedValues + 1); setName(NameStr); } -CatchPadInst::CatchPadInst(const CatchPadInst &CPI) - : TerminatorInst(CPI.getType(), Instruction::CatchPad, - OperandTraits::op_end(this) - - CPI.getNumOperands(), - CPI.getNumOperands()) { - std::copy(CPI.op_begin(), CPI.op_end(), op_begin()); +CatchSwitchInst::CatchSwitchInst(Value *OuterScope, BasicBlock *UnwindDest, + unsigned NumReservedValues, + const Twine &NameStr, BasicBlock *InsertAtEnd) + : TerminatorInst(OuterScope->getType(), Instruction::CatchSwitch, nullptr, + 0, InsertAtEnd) { + if (UnwindDest) + ++NumReservedValues; + init(OuterScope, UnwindDest, NumReservedValues + 1); + setName(NameStr); } -CatchPadInst::CatchPadInst(BasicBlock *IfNormal, BasicBlock *IfException, - ArrayRef Args, unsigned Values, - const Twine &NameStr, Instruction *InsertBefore) - : TerminatorInst(Type::getTokenTy(IfNormal->getContext()), - Instruction::CatchPad, - OperandTraits::op_end(this) - Values, Values, - InsertBefore) { - init(IfNormal, IfException, Args, NameStr); +CatchSwitchInst::CatchSwitchInst(const CatchSwitchInst &CSI) + : TerminatorInst(CSI.getType(), Instruction::CatchSwitch, nullptr, + CSI.getNumOperands()) { + init(CSI.getParentPad(), CSI.getUnwindDest(), CSI.getNumOperands()); + setNumHungOffUseOperands(ReservedSpace); + Use *OL = getOperandList(); + const Use *InOL = CSI.getOperandList(); + for (unsigned I = 1, E = ReservedSpace; I != E; ++I) + OL[I] = InOL[I]; } -CatchPadInst::CatchPadInst(BasicBlock *IfNormal, BasicBlock *IfException, - ArrayRef Args, unsigned Values, - const Twine &NameStr, BasicBlock *InsertAtEnd) - : TerminatorInst(Type::getTokenTy(IfNormal->getContext()), - Instruction::CatchPad, - OperandTraits::op_end(this) - Values, Values, - InsertAtEnd) { - init(IfNormal, IfException, Args, NameStr); +void CatchSwitchInst::init(Value *OuterScope, BasicBlock *UnwindDest, + unsigned NumReservedValues) { + assert(OuterScope && NumReservedValues); + + ReservedSpace = NumReservedValues; + setNumHungOffUseOperands(UnwindDest ? 2 : 1); + allocHungoffUses(ReservedSpace); + + Op<0>() = OuterScope; + if (UnwindDest) { + setInstructionSubclassData(getSubclassDataFromInstruction() | 1); + setUnwindDest(UnwindDest); + } } -BasicBlock *CatchPadInst::getSuccessorV(unsigned Idx) const { - return getSuccessor(Idx); +/// growOperands - grow operands - This grows the operand list in response to a +/// push_back style of operation. This grows the number of ops by 2 times. +void CatchSwitchInst::growOperands(unsigned Size) { + unsigned NumOperands = getNumOperands(); + assert(NumOperands >= 1); + if (ReservedSpace >= NumOperands + Size) + return; + ReservedSpace = (NumOperands + Size / 2) * 2; + growHungoffUses(ReservedSpace); } -unsigned CatchPadInst::getNumSuccessorsV() const { + +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 *OuterScope, ArrayRef Args, + const Twine &NameStr) { + assert(getNumOperands() == 1 + Args.size() && "NumOperands not set up?"); + std::copy(Args.begin(), Args.end(), op_begin()); + setParentPad(OuterScope); + setName(NameStr); +} + +FuncletPadInst::FuncletPadInst(const FuncletPadInst &FPI) + : Instruction(FPI.getType(), FPI.getOpcode(), + OperandTraits::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 *OuterScope, + ArrayRef Args, unsigned Values, + const Twine &NameStr, Instruction *InsertBefore) + : Instruction(OuterScope->getType(), Op, + OperandTraits::op_end(this) - Values, Values, + InsertBefore) { + init(OuterScope, Args, NameStr); +} + +FuncletPadInst::FuncletPadInst(Instruction::FuncletPadOps Op, Value *OuterScope, + ArrayRef Args, unsigned Values, + const Twine &NameStr, BasicBlock *InsertAtEnd) + : Instruction(OuterScope->getType(), Op, + OperandTraits::op_end(this) - Values, Values, + InsertAtEnd) { + init(OuterScope, Args, NameStr); } //===----------------------------------------------------------------------===// // TerminatePadInst Implementation //===----------------------------------------------------------------------===// -void TerminatePadInst::init(BasicBlock *BB, ArrayRef Args) { - if (BB) +void TerminatePadInst::init(Value *OuterScope, BasicBlock *BB, + ArrayRef 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(OuterScope); } TerminatePadInst::TerminatePadInst(const TerminatePadInst &TPI) @@ -1036,22 +1002,24 @@ std::copy(TPI.op_begin(), TPI.op_end(), op_begin()); } -TerminatePadInst::TerminatePadInst(LLVMContext &C, BasicBlock *BB, +TerminatePadInst::TerminatePadInst(Value *OuterScope, BasicBlock *BB, ArrayRef Args, unsigned Values, Instruction *InsertBefore) - : TerminatorInst(Type::getVoidTy(C), Instruction::TerminatePad, + : TerminatorInst(Type::getVoidTy(OuterScope->getContext()), + Instruction::TerminatePad, OperandTraits::op_end(this) - Values, Values, InsertBefore) { - init(BB, Args); + init(OuterScope, BB, Args); } -TerminatePadInst::TerminatePadInst(LLVMContext &C, BasicBlock *BB, +TerminatePadInst::TerminatePadInst(Value *OuterScope, BasicBlock *BB, ArrayRef Args, unsigned Values, BasicBlock *InsertAtEnd) - : TerminatorInst(Type::getVoidTy(C), Instruction::TerminatePad, + : TerminatorInst(Type::getVoidTy(OuterScope->getContext()), + Instruction::TerminatePad, OperandTraits::op_end(this) - Values, Values, InsertAtEnd) { - init(BB, Args); + init(OuterScope, BB, Args); } BasicBlock *TerminatePadInst::getSuccessorV(unsigned Idx) const { @@ -1067,39 +1035,6 @@ } //===----------------------------------------------------------------------===// -// CleanupPadInst Implementation -//===----------------------------------------------------------------------===// -void CleanupPadInst::init(ArrayRef 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::op_end(this) - - CPI.getNumOperands(), - CPI.getNumOperands()) { - std::copy(CPI.op_begin(), CPI.op_end(), op_begin()); -} - -CleanupPadInst::CleanupPadInst(LLVMContext &C, ArrayRef Args, - const Twine &NameStr, Instruction *InsertBefore) - : Instruction(Type::getTokenTy(C), Instruction::CleanupPad, - OperandTraits::op_end(this) - Args.size(), - Args.size(), InsertBefore) { - init(Args, NameStr); -} - -CleanupPadInst::CleanupPadInst(LLVMContext &C, ArrayRef Args, - const Twine &NameStr, BasicBlock *InsertAtEnd) - : Instruction(Type::getTokenTy(C), Instruction::CleanupPad, - OperandTraits::op_end(this) - Args.size(), - Args.size(), InsertAtEnd) { - init(Args, NameStr); -} - -//===----------------------------------------------------------------------===// // UnreachableInst Implementation //===----------------------------------------------------------------------===// @@ -4072,32 +4007,24 @@ ResumeInst *ResumeInst::cloneImpl() const { return new (1) ResumeInst(*this); } -CleanupEndPadInst *CleanupEndPadInst::cloneImpl() const { - return new (getNumOperands()) CleanupEndPadInst(*this); -} - CleanupReturnInst *CleanupReturnInst::cloneImpl() const { return new (getNumOperands()) CleanupReturnInst(*this); } -CatchEndPadInst *CatchEndPadInst::cloneImpl() const { - return new (getNumOperands()) CatchEndPadInst(*this); -} - CatchReturnInst *CatchReturnInst::cloneImpl() const { return new (getNumOperands()) CatchReturnInst(*this); } -CatchPadInst *CatchPadInst::cloneImpl() const { - return new (getNumOperands()) CatchPadInst(*this); +CatchSwitchInst *CatchSwitchInst::cloneImpl() const { + return new CatchSwitchInst(*this); } -TerminatePadInst *TerminatePadInst::cloneImpl() const { - return new (getNumOperands()) TerminatePadInst(*this); +FuncletPadInst *FuncletPadInst::cloneImpl() const { + return new (getNumOperands()) FuncletPadInst(*this); } -CleanupPadInst *CleanupPadInst::cloneImpl() const { - return new (getNumOperands()) CleanupPadInst(*this); +TerminatePadInst *TerminatePadInst::cloneImpl() const { + return new (getNumOperands()) TerminatePadInst(*this); } UnreachableInst *UnreachableInst::cloneImpl() const { Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -399,9 +399,9 @@ 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 @@ } return; } + if (auto *CPI = dyn_cast(&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(TI)) + if (auto *II = dyn_cast(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(TI)) - Assert(CPI->getUnwindDest() == BB && CPI->getNormalDest() != BB, - "EH pad must be jumped to via an unwind edge", &I, CPI); - else if (isa(TI)) - ; - else if (isa(TI)) - ; - else if (isa(TI)) - ; - else if (isa(TI)) - ; - else + } else if (!isa(TI) && !isa(TI) && + !isa(TI)) { Assert(false, "EH pad must be jumped to via an unwind edge", &I, TI); + } } } @@ -2952,67 +2951,29 @@ 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(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); - - if (!BB->getSinglePredecessor()) - for (BasicBlock *PredBB : predecessors(BB)) { - Assert(!isa(PredBB->getTerminator()), - "CatchPadInst with CatchPadInst predecessor cannot have any other " - "predecessors.", - &CPI); - } - - BasicBlock *UnwindDest = CPI.getUnwindDest(); - Instruction *I = UnwindDest->getFirstNonPHI(); - Assert( - isa(I) || isa(I), - "CatchPadInst must unwind to a CatchPadInst or a CatchEndPadInst.", - &CPI); + "CatchPadInst not the first non-PHI instruction in the block.", &CPI); - visitTerminatorInst(CPI); + visitInstruction(CPI); } -void Verifier::visitCatchEndPadInst(CatchEndPadInst &CEPI) { - visitEHPadPredecessors(CEPI); - - BasicBlock *BB = CEPI.getParent(); - Function *F = BB->getParent(); - Assert(F->hasPersonalityFn(), - "CatchEndPadInst needs to be in a function with a personality.", - &CEPI); - - // The catchendpad instruction must be the first non-PHI instruction in the - // block. - Assert(BB->getFirstNonPHI() == &CEPI, - "CatchEndPadInst not the first non-PHI instruction in the block.", - &CEPI); +void Verifier::visitCatchReturnInst(CatchReturnInst &CatchReturn) { + Assert(isa(CatchReturn.getOperand(0)), + "CatchReturnInst needs to be provided a CatchPad", &CatchReturn, + CatchReturn.getOperand(0)); - unsigned CatchPadsSeen = 0; - for (BasicBlock *PredBB : predecessors(BB)) - if (isa(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(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,82 @@ "CleanupPadInst not the first non-PHI instruction in the block.", &CPI); + auto *OuterScope = CPI.getParentPad(); + Assert(isa(OuterScope) || + isa(OuterScope) || + isa(OuterScope) || + isa(OuterScope), + "CleanupPadInst has an invalid outer scope.", + &CPI); + User *FirstUser = nullptr; BasicBlock *FirstUnwindDest = nullptr; for (User *U : CPI.users()) { BasicBlock *UnwindDest; if (CleanupReturnInst *CRI = dyn_cast(U)) { UnwindDest = CRI->getUnwindDest(); + } else if (isa(U) || isa(U) || + isa(U)) { + continue; } else { - UnwindDest = cast(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(I), - "CleanupEndPad must unwind to an EH block which is not a landingpad.", - &CEPI); + Assert(I->isEHPad() && !isa(I), + "CatchSwitchInst must unwind to an EH block which is not a " + "landingpad.", + &CatchSwitch); } - visitTerminatorInst(CEPI); + auto *OuterScope = CatchSwitch.getParentPad(); + Assert(isa(OuterScope) || + isa(OuterScope) || + isa(OuterScope) || + isa(OuterScope), + "CatchSwitchInst has an invalid outer scope.", + OuterScope); + + visitTerminatorInst(CatchSwitch); } void Verifier::visitCleanupReturnInst(CleanupReturnInst &CRI) { + Assert(isa(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(I), @@ -3115,6 +3101,14 @@ &TPI); } + auto *OuterScope = TPI.getParentPad(); + Assert(isa(OuterScope) || + isa(OuterScope) || + isa(OuterScope) || + isa(OuterScope), + "TerminatePadInst has an invalid outer scope.", + OuterScope); + visitTerminatorInst(TPI); } Index: lib/Target/X86/X86WinEHState.cpp =================================================================== --- lib/Target/X86/X86WinEHState.cpp +++ lib/Target/X86/X86WinEHState.cpp @@ -15,6 +15,7 @@ //===----------------------------------------------------------------------===// #include "X86.h" +#include "llvm/Analysis/CFG.h" #include "llvm/Analysis/EHPersonalities.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/Passes.h" @@ -416,20 +417,33 @@ calculateWinCXXEHStateNumbers(&F, FuncInfo); // Iterate all the instructions and emit state number stores. + DenseMap 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(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(&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(&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); } } Index: lib/Transforms/Instrumentation/MemorySanitizer.cpp =================================================================== --- lib/Transforms/Instrumentation/MemorySanitizer.cpp +++ lib/Transforms/Instrumentation/MemorySanitizer.cpp @@ -2684,12 +2684,12 @@ 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 @@ // 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); } Index: lib/Transforms/Scalar/Reassociate.cpp =================================================================== --- lib/Transforms/Scalar/Reassociate.cpp +++ lib/Transforms/Scalar/Reassociate.cpp @@ -947,8 +947,6 @@ if (Instruction *InstInput = dyn_cast(V)) { if (InvokeInst *II = dyn_cast(InstInput)) { InsertPt = II->getNormalDest()->begin(); - } else if (auto *CPI = dyn_cast(InstInput)) { - InsertPt = CPI->getNormalDest()->begin(); } else { InsertPt = ++InstInput->getIterator(); } Index: lib/Transforms/Scalar/SCCP.cpp =================================================================== --- lib/Transforms/Scalar/SCCP.cpp +++ lib/Transforms/Scalar/SCCP.cpp @@ -480,8 +480,10 @@ 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); } Index: lib/Transforms/Scalar/Sink.cpp =================================================================== --- lib/Transforms/Scalar/Sink.cpp +++ lib/Transforms/Scalar/Sink.cpp @@ -169,7 +169,8 @@ return false; } - if (isa(Inst) || isa(Inst) || Inst->isEHPad()) + if (isa(Inst) || isa(Inst) || Inst->isEHPad() || + Inst->mayThrow()) return false; // Convergent operations cannot be made control-dependent on additional @@ -194,6 +195,11 @@ 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. Index: lib/Transforms/Utils/CodeExtractor.cpp =================================================================== --- lib/Transforms/Utils/CodeExtractor.cpp +++ lib/Transforms/Utils/CodeExtractor.cpp @@ -560,8 +560,8 @@ // 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(outputs[out])->getParent(); bool DominatesDef = true; @@ -569,8 +569,6 @@ BasicBlock *NormalDest = nullptr; if (auto *Invoke = dyn_cast(outputs[out])) NormalDest = Invoke->getNormalDest(); - if (auto *CatchPad = dyn_cast(outputs[out])) - NormalDest = CatchPad->getNormalDest(); if (NormalDest) { DefBlock = NormalDest; Index: lib/Transforms/Utils/InlineFunction.cpp =================================================================== --- lib/Transforms/Utils/InlineFunction.cpp +++ lib/Transforms/Utils/InlineFunction.cpp @@ -21,6 +21,7 @@ #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/CaptureTracking.h" +#include "llvm/Analysis/EHPersonalities.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Attributes.h" @@ -192,8 +193,6 @@ // instructions require no special handling. CallInst *CI = dyn_cast(I); - // If this call cannot unwind, don't convert it to an invoke. - // Inline asm calls cannot throw. if (!CI || CI->doesNotThrow() || isa(CI->getCalledValue())) continue; @@ -327,40 +326,10 @@ } }; - // 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(I)) { - if (CEPI->unwindsToCaller()) { - CatchEndPadInst::Create(CEPI->getContext(), UnwindDest, CEPI); - CEPI->eraseFromParent(); - UpdatePHINodes(&*BB); - } - } else if (auto *CEPI = dyn_cast(I)) { - if (CEPI->unwindsToCaller()) { - CleanupEndPadInst::Create(CEPI->getCleanupPad(), UnwindDest, CEPI); - CEPI->eraseFromParent(); - UpdatePHINodes(&*BB); - } - } else if (auto *TPI = dyn_cast(I)) { - if (TPI->unwindsToCaller()) { - SmallVector 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(I) || isa(I)); - } - } - if (auto *CRI = dyn_cast(BB->getTerminator())) { if (CRI->unwindsToCaller()) { CleanupReturnInst::Create(CRI->getCleanupPad(), UnwindDest, CRI); @@ -368,6 +337,40 @@ UpdatePHINodes(&*BB); } } + + Instruction *I = BB->getFirstNonPHI(); + if (!I->isEHPad()) + continue; + + Instruction *Replacement = nullptr; + if (auto *TPI = dyn_cast(I)) { + if (TPI->unwindsToCaller()) { + SmallVector 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(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(I)) { + llvm_unreachable("unexpected EHPad!"); + } + + if (Replacement) { + Replacement->takeName(I); + I->replaceAllUsesWith(Replacement); + I->eraseFromParent(); + UpdatePHINodes(&*BB); + } } if (InlinedCodeInfo.ContainsCalls) @@ -1090,6 +1093,53 @@ 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 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(CallSiteEHPad)) { + // Ok, the call site is within a cleanuppad. Let's check the callee + // for catchpads. + for (const BasicBlock &CalledBB : *CalledFunc) { + if (isa(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 @@ } } + // 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(I)) { + if (isa(TPI->getParentPad())) + TPI->setParentPad(CallSiteEHPad); + } else if (auto *CatchSwitch = dyn_cast(I)) { + if (isa(CatchSwitch->getParentPad())) + CatchSwitch->setParentPad(CallSiteEHPad); + } else { + auto *FPI = cast(I); + if (isa(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(TheCall)) { Index: lib/Transforms/Utils/LCSSA.cpp =================================================================== --- lib/Transforms/Utils/LCSSA.cpp +++ lib/Transforms/Utils/LCSSA.cpp @@ -84,15 +84,13 @@ ++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(&Inst)) DomBB = Inv->getNormalDest(); - if (auto *CPI = dyn_cast(&Inst)) - DomBB = CPI->getNormalDest(); DomTreeNode *DomNode = DT.getNode(DomBB); Index: lib/Transforms/Utils/Local.cpp =================================================================== --- lib/Transforms/Utils/Local.cpp +++ lib/Transforms/Utils/Local.cpp @@ -1338,19 +1338,22 @@ if (auto *CRI = dyn_cast(TI)) { NewTI = CleanupReturnInst::Create(CRI->getCleanupPad(), nullptr, CRI); UnwindDest = CRI->getUnwindDest(); - } else if (auto *CEP = dyn_cast(TI)) { - NewTI = CleanupEndPadInst::Create(CEP->getCleanupPad(), nullptr, CEP); - UnwindDest = CEP->getUnwindDest(); - } else if (auto *CEP = dyn_cast(TI)) { - NewTI = CatchEndPadInst::Create(CEP->getContext(), nullptr, CEP); - UnwindDest = CEP->getUnwindDest(); } else if (auto *TPI = dyn_cast(TI)) { SmallVector 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(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 @@ NewTI->takeName(TI); NewTI->setDebugLoc(TI->getDebugLoc()); UnwindDest->removePredecessor(BB); + TI->replaceAllUsesWith(NewTI); TI->eraseFromParent(); } Index: lib/Transforms/Utils/SimplifyCFG.cpp =================================================================== --- lib/Transforms/Utils/SimplifyCFG.cpp +++ lib/Transforms/Utils/SimplifyCFG.cpp @@ -3254,8 +3254,8 @@ // updated to continue to the unwind destination of the cleanup pad being // simplified. BasicBlock *BB = RI->getParent(); - Instruction *CPInst = dyn_cast(BB->getFirstNonPHI()); - if (!CPInst) + CleanupPadInst *CPInst = RI->getCleanupPad(); + if (CPInst->getParent() != BB) // This isn't an empty cleanup. return false; @@ -3265,9 +3265,10 @@ if (!isa(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 @@ // 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(I); @@ -3322,7 +3323,7 @@ } // 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 @@ } } else if ((isa(TI) && cast(TI)->getUnwindDest() == BB) || - isa(TI) || isa(TI)) { + isa(TI) || isa(TI)) { removeUnwindEdge(TI->getParent()); Changed = true; - } else if (isa(TI) || isa(TI)) { + } else if (isa(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. Index: test/Assembler/invalid-OperatorConstraint.ll =================================================================== --- test/Assembler/invalid-OperatorConstraint.ll +++ /dev/null @@ -1,89 +0,0 @@ -; RUN: sed -e s/.T1:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK1 %s -; RUN: sed -e s/.T2:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK2 %s -; RUN: sed -e s/.T3:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK3 %s -; RUN: sed -e s/.T4:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK4 %s -; RUN: sed -e s/.T5:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK5 %s -; RUN: sed -e s/.T6:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK6 %s -; RUN: sed -e s/.T7:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK7 %s -; RUN: sed -e s/.T8:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK8 %s -; RUN: sed -e s/.T9:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK9 %s - -;T1: define void @f() { -;T1: entry: -;T1: ; operator constraint requires an operator -;T1: catchret undef to label %entry -;T1: ; CHECK1: [[@LINE-1]]:15: error: Catchpad value required in this position -;T1: } - -;T2: define void @f() { -;T2: entry: -;T2: %x = cleanuppad [] -;T2: ; catchret's first operand's operator must be catchpad -;T2: catchret %x to label %entry -;T2: ; CHECK2: [[@LINE-1]]:15: error: '%x' is not a catchpad -;T2: } - -;T3: define void @f() { -;T3: entry: -;T3: ; catchret's first operand's operator must be catchpad -;T3: ; (forward reference case) -;T3: catchret %x to label %next -;T3: ; CHECK3: [[@LINE-1]]:15: error: '%x' is not a catchpad -;T3: next: -;T3: %x = cleanuppad [] -;T3: ret void -;T3: } - -;T4: define void @f() { -;T4: entry: -;T4: ; operator constraint requires an operator -;T4: cleanupret undef unwind label %entry -;T4: ; CHECK4: [[@LINE-1]]:17: error: Cleanuppad value required in this position -;T4: } - -;T5: define void @f() { -;T5: entry: -;T5: %x = catchpad [] -;T5: to label %next unwind label %entry -;T5: next: -;T5: ; cleanupret first operand's operator must be cleanuppad -;T5: cleanupret %x unwind to caller -;T5: ; CHECK5: [[@LINE-1]]:17: error: '%x' is not a cleanuppad -;T5: } - -;T6: define void @f() { -;T6: entry: -;T6: ; cleanupret's first operand's operator must be cleanuppad -;T6: ; (forward reference case) -;T6: cleanupret %x unwind label %next -;T6: ; CHECK6: [[@LINE-1]]:17: error: '%x' is not a cleanuppad -;T6: next: -;T6: %x = catchpad [] to label %entry unwind label %next -;T6: } - -;T7: define void @f() { -;T7: entry: -;T7: ; operator constraint requires an operator -;T7: cleanupendpad undef unwind to caller -;T7: ; CHECK7: [[@LINE-1]]:20: error: Cleanuppad value required in this position -;T7: } - -;T8: define void @f() { -;T8: entry: -;T8: %x = catchpad [] -;T8: to label %next unwind label %entry -;T8: next: -;T8: ; cleanupret first operand's operator must be cleanuppad -;T8: cleanupendpad %x unwind label next -;T8: ; CHECK8: [[@LINE-1]]:20: error: '%x' is not a cleanuppad -;T8: } - -;T9: define void @f() { -;T9: entry: -;T9: ; cleanupret's first operand's operator must be cleanuppad -;T9: ; (forward reference case) -;T9: cleanupendpad %x unwind label %next -;T9: ; CHECK9: [[@LINE-1]]:20: error: '%x' is not a cleanuppad -;T9: next: -;T9: %x = catchpad [] to label %entry unwind label %next -;T9: } Index: test/Bitcode/compatibility.ll =================================================================== --- test/Bitcode/compatibility.ll +++ test/Bitcode/compatibility.ll @@ -769,95 +769,91 @@ entry: %arg1 = alloca i32 %arg2 = alloca i32 - invoke void @f.ccc() to label %normal unwind label %catchpad1 - invoke void @f.ccc() to label %normal unwind label %catchpad2 - invoke void @f.ccc() to label %normal unwind label %catchpad3 + invoke void @f.ccc() to label %normal unwind label %catchswitch1 + invoke void @f.ccc() to label %normal unwind label %catchswitch2 + invoke void @f.ccc() to label %normal unwind label %catchswitch3 + +catchswitch1: + %cs1 = catchswitch within none [label %catchpad1] unwind label %terminate.1 catchpad1: - catchpad [] to label %normal unwind label %exn.1 - ; CHECK: catchpad [] - ; CHECK-NEXT: to label %normal unwind label %exn.1 + catchpad within %cs1 [] + br label %normal + ; CHECK: catchpad within %cs1 [] + ; CHECK-NEXT: br label %normal -catchpad2: - catchpad [i32* %arg1] to label %normal unwind label %exn.2 - ; CHECK: catchpad [i32* %arg1] - ; CHECK-NEXT: to label %normal unwind label %exn.2 +catchswitch2: + %cs2 = catchswitch within none [label %catchpad2] unwind to caller -catchpad3: - catchpad [i32* %arg1, i32* %arg2] to label %normal unwind label %exn.3 - ; CHECK: catchpad [i32* %arg1, i32* %arg2] - ; CHECK-NEXT: to label %normal unwind label %exn.3 - -exn.1: - catchendpad unwind label %terminate.1 - ; CHECK: catchendpad unwind label %terminate.1 +catchpad2: + catchpad within %cs2 [i32* %arg1] + br label %normal + ; CHECK: catchpad within %cs2 [i32* %arg1] + ; CHECK-NEXT: br label %normal -exn.2: - catchendpad unwind to caller - ; CHECK: catchendpad unwind to caller +catchswitch3: + %cs3 = catchswitch within none [label %catchpad3] unwind label %cleanuppad1 -exn.3: - catchendpad unwind label %cleanuppad1 - ; CHECK: catchendpad unwind label %cleanuppad1 +catchpad3: + catchpad within %cs3 [i32* %arg1, i32* %arg2] + br label %normal + ; CHECK: catchpad within %cs3 [i32* %arg1, i32* %arg2] + ; CHECK-NEXT: br label %normal cleanuppad1: - %clean.1 = cleanuppad [] - ; CHECK: %clean.1 = cleanuppad [] - invoke void @f.ccc() to label %normal unwind label %cleanupendpad1 - -cleanupendpad1: - cleanupendpad %clean.1 unwind label %terminate.2 - ; CHECK: cleanupendpad %clean.1 unwind label %terminate.2 + %clean.1 = cleanuppad within none [] + ; CHECK: %clean.1 = cleanuppad within none [] + invoke void @f.ccc() to label %normal unwind label %terminate.2 terminate.1: - terminatepad [] unwind to caller - ; CHECK: terminatepad [] unwind to caller + terminatepad within none [] unwind to caller + ; CHECK: terminatepad within none [] unwind to caller terminate.2: - terminatepad [i32* %arg1] unwind label %normal.pre - ; CHECK: terminatepad [i32* %arg1] unwind label %normal.pre + terminatepad within %clean.1 [i32* %arg1] unwind label %normal.pre + ; CHECK: terminatepad within %clean.1 [i32* %arg1] unwind label %normal.pre normal.pre: - terminatepad [i32* %arg1, i32* %arg2] unwind to caller - ; CHECK: terminatepad [i32* %arg1, i32* %arg2] unwind to caller + terminatepad within %clean.1 [i32* %arg1, i32* %arg2] unwind to caller + ; CHECK: terminatepad within %clean.1 [i32* %arg1, i32* %arg2] unwind to caller normal: ret i32 0 } - +; define i32 @instructions.win_eh.2() personality i32 -4 { entry: - invoke void @f.ccc() to label %invoke.cont unwind label %catchpad + invoke void @f.ccc() to label %invoke.cont unwind label %catchswitch invoke.cont: invoke void @f.ccc() to label %continue unwind label %cleanup cleanup: - %clean = cleanuppad [] - ; CHECK: %clean = cleanuppad [] - cleanupret %clean unwind to caller - ; CHECK: cleanupret %clean unwind to caller + %clean = cleanuppad within none [] + ; CHECK: %clean = cleanuppad within none [] + cleanupret from %clean unwind to caller + ; CHECK: cleanupret from %clean unwind to caller + +catchswitch: + %cs = catchswitch within none [label %catchpad] unwind label %terminate catchpad: - %catch = catchpad [] to label %body unwind label %catchend - ; CHECK: %catch = catchpad [] - ; CHECK-NEXT: to label %body unwind label %catchend + %catch = catchpad within %cs [] + br label %body + ; CHECK: %catch = catchpad within %cs [] + ; CHECK-NEXT: br label %body body: - invoke void @f.ccc() to label %continue unwind label %catchend - catchret %catch to label %return - ; CHECK: catchret %catch to label %return + invoke void @f.ccc() to label %continue unwind label %terminate + catchret from %catch to label %return + ; CHECK: catchret from %catch to label %return return: ret i32 0 -catchend: - catchendpad unwind label %terminate - ; CHECK: catchendpad unwind label %terminate - terminate: - terminatepad [] unwind to caller - ; CHECK: terminatepad [] unwind to caller + terminatepad within %cs [] unwind to caller + ; CHECK: terminatepad within %cs [] unwind to caller continue: ret i32 0 Index: test/CodeGen/WinEH/wineh-cloning.ll =================================================================== --- test/CodeGen/WinEH/wineh-cloning.ll +++ test/CodeGen/WinEH/wineh-cloning.ll @@ -1,6 +1,7 @@ -; RUN: opt -mtriple=x86_x64-pc-windows-msvc -S -winehprepare < %s | FileCheck %s +; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -winehprepare < %s | FileCheck %s declare i32 @__CxxFrameHandler3(...) +declare i32 @__C_specific_handler(...) declare void @f() declare i32 @g() @@ -13,16 +14,16 @@ ; %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 @@ ; 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 @@ 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 @@ ; 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 @@ 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 @@ ; 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 @@ 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 void @f() to label %exit unwind label %right left: - cleanuppad [] + cleanuppad within none [] br label %shared right: - catchpad [] - to label %right.catch unwind label %right.end + %cs = catchswitch within none [label %right.catch] unwind to caller right.catch: + catchpad within %cs [] br label %shared -right.end: - catchendpad unwind to caller shared: %x = call i32 @g() invoke void @f() @@ -259,109 +253,32 @@ shared.cont: unreachable inner: - %i = cleanuppad [] + %i = cleanuppad within none [] call void @h(i32 %x) - cleanupret %i unwind label %right.end + cleanupret from %i unwind to caller exit: ret void } -; %inner is a cleanup which appears both as a child of -; %left and as a child of %right. Since statically we -; need each funclet to have a single parent, we need to -; clone the entire %inner funclet so we can have one -; copy under each parent. The cleanupret in %inner -; unwinds to the catchendpad for %right, so the copy -; of %inner under %right should include it; the copy -; of %inner under %left should instead have an -; `unreachable` inserted there, but the copy under -; %left still needs to be created because it's possible -; the dynamic path enters %left, then enters %inner, -; then calls @h, and that the call to @h doesn't return. ; CHECK-LABEL: define void @test6( ; CHECK: left: ; CHECK: %x.for.left = call i32 @g() ; CHECK: invoke void @f() -; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]] -; CHECK: right: -; CHECK: catchpad -; CHECK: to label %right.catch unwind label %right.end +; CHECK: to label %shared.cont.for.left unwind label %inner ; CHECK: right.catch: +; CHECK: catchpad ; CHECK: %x = call i32 @g() -; CHECK: to label %shared.cont unwind label %[[INNER_RIGHT:.+]] -; CHECK: right.end: -; CHECK: catchendpad unwind to caller +; CHECK: to label %shared.cont unwind label %inner ; CHECK: shared.cont: ; CHECK: unreachable -; CHECK: [[SHARED_CONT_LEFT]]: -; CHECK: unreachable -; CHECK: [[INNER_RIGHT]]: -; CHECK: [[I_R:\%.+]] = cleanuppad [] -; CHECK: call void @h(i32 %x) -; CHECK: cleanupret [[I_R]] unwind label %right.end -; CHECK: [[INNER_LEFT]]: -; CHECK: [[I_L:\%.+]] = cleanuppad [] -; CHECK: call void @h(i32 %x.for.left) -; CHECK: unreachable - - -define void @test7() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %invoke.cont unwind label %left -invoke.cont: - invoke void @f() - to label %unreachable unwind label %right -left: - cleanuppad [] - invoke void @f() to label %unreachable unwind label %inner -right: - catchpad [] - to label %right.catch unwind label %right.end -right.catch: - invoke void @f() to label %unreachable unwind label %inner -right.end: - catchendpad unwind to caller -inner: - %i = cleanuppad [] - %x = call i32 @g() - call void @h(i32 %x) - cleanupret %i unwind label %right.end -unreachable: - unreachable -} -; Another case of a two-parent child (like @test6), this time -; with the join at the entry itself instead of following a -; non-pad join. -; CHECK-LABEL: define void @test7( -; CHECK: invoke.cont: -; CHECK: to label %[[UNREACHABLE_ENTRY:.+]] unwind label %right -; CHECK: left: -; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_LEFT:.+]] -; CHECK: right: -; CHECK: to label %right.catch unwind label %right.end -; CHECK: right.catch: -; CHECK: to label %unreachable unwind label %[[INNER_RIGHT:.+]] -; CHECK: right.end: -; CHECK: catchendpad unwind to caller -; CHECK: [[INNER_RIGHT]]: -; CHECK: [[I_R:\%.+]] = cleanuppad [] -; CHECK: [[X_R:\%.+]] = call i32 @g() -; CHECK: call void @h(i32 [[X_R]]) -; CHECK: cleanupret [[I_R]] unwind label %right.end -; CHECK: [[INNER_LEFT]]: -; CHECK: [[I_L:\%.+]] = cleanuppad [] -; CHECK: [[X_L:\%.+]] = call i32 @g() -; CHECK: call void @h(i32 [[X_L]]) -; CHECK: unreachable -; CHECK: unreachable: -; CHECK: unreachable -; CHECK: [[UNREACHABLE_LEFT]]: -; CHECK: unreachable -; CHECK: [[UNREACHABLE_ENTRY]]: +; CHECK: shared.cont.for.left: ; CHECK: unreachable +; CHECK: inner: +; CHECK: %i = cleanuppad within none [] +; CHECK: call void @h(i32 %x1.wineh.reload) +; CHECK: cleanupret from %i unwind to caller -define void @test8() personality i32 (...)* @__CxxFrameHandler3 { +define void @test9() personality i32 (...)* @__C_specific_handler { entry: invoke void @f() to label %invoke.cont unwind label %left @@ -369,119 +286,32 @@ invoke 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 @@ 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 @@ ; 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 @@ 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 @@ 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 Index: test/CodeGen/WinEH/wineh-demotion.ll =================================================================== --- test/CodeGen/WinEH/wineh-demotion.ll +++ test/CodeGen/WinEH/wineh-demotion.ll @@ -1,4 +1,4 @@ -; RUN: opt -mtriple=x86_x64-pc-windows-msvc -S -winehprepare < %s | FileCheck %s +; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -winehprepare < %s | FileCheck %s declare i32 @__CxxFrameHandler3(...) @@ -36,17 +36,15 @@ ; 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 @@ 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 @@ 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 @@ %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 @@ 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 @@ ; 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 @@ ; 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 @@ %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 @@ 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 @@ ; 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 @@ 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 } Index: test/CodeGen/WinEH/wineh-intrinsics.ll =================================================================== --- test/CodeGen/WinEH/wineh-intrinsics.ll +++ test/CodeGen/WinEH/wineh-intrinsics.ll @@ -15,13 +15,12 @@ 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 @@ 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 } Index: test/CodeGen/WinEH/wineh-multi-parent-cloning.ll =================================================================== --- test/CodeGen/WinEH/wineh-multi-parent-cloning.ll +++ /dev/null @@ -1,1548 +0,0 @@ -; RUN: opt -mtriple=x86_x64-pc-windows-msvc -S -winehprepare < %s | FileCheck %s - -declare i32 @__CxxFrameHandler3(...) - -declare void @f() -declare i32 @g() -declare void @h(i32) -declare i1 @b() - -define void @test1() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %invoke.cont unwind label %left -invoke.cont: - invoke void @f() - to label %exit unwind label %right -left: - cleanuppad [] - br label %shared -right: - catchpad [] - to label %right.catch unwind label %right.end -right.catch: - br label %shared -right.end: - catchendpad unwind to caller -shared: - %x = call i32 @g() - invoke void @f() - to label %shared.cont unwind label %inner -shared.cont: - unreachable -inner: - %i = cleanuppad [] - call void @h(i32 %x) - cleanupret %i unwind label %right.end -exit: - ret void -} -; %inner is a cleanup which appears both as a child of -; %left and as a child of %right. Since statically we -; need each funclet to have a single parent, we need to -; clone the entire %inner funclet so we can have one -; copy under each parent. The cleanupret in %inner -; unwinds to the catchendpad for %right, so the copy -; of %inner under %right should include it; the copy -; of %inner under %left should instead have an -; `unreachable` inserted there, but the copy under -; %left still needs to be created because it's possible -; the dynamic path enters %left, then enters %inner, -; then calls @h, and that the call to @h doesn't return. -; CHECK-LABEL: define void @test1( -; CHECK: left: -; CHECK: cleanuppad -; CHECK: %x.for.left = call i32 @g() -; CHECK: invoke void @f() -; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]] -; CHECK: right: -; CHECK: to label %right.catch unwind label %right.end -; CHECK: right.catch: -; CHECK: %x = call i32 @g() -; CHECK: to label %shared.cont unwind label %[[INNER_RIGHT:.+]] -; CHECK: right.end: -; CHECK: catchendpad unwind to caller -; CHECK: shared.cont: -; CHECK: unreachable -; CHECK: [[SHARED_CONT_LEFT]]: -; CHECK: unreachable -; CHECK: [[INNER_RIGHT]]: -; CHECK: [[I_R:\%.+]] = cleanuppad [] -; CHECK: call void @h(i32 %x) -; CHECK: cleanupret [[I_R]] unwind label %right.end -; CHECK: [[INNER_LEFT]]: -; CHECK: [[I_L:\%.+]] = cleanuppad [] -; CHECK: call void @h(i32 %x.for.left) -; CHECK: unreachable - - -define void @test2() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %invoke.cont unwind label %left -invoke.cont: - invoke void @f() - to label %exit unwind label %right -left: - cleanuppad [] - br label %shared -right: - catchpad [] - to label %right.catch unwind label %right.end -right.catch: - br label %shared -right.end: - catchendpad unwind to caller -shared: - %x = call i32 @g() - invoke void @f() - to label %shared.cont unwind label %inner -shared.cont: - unreachable -inner: - catchpad [] - to label %inner.catch unwind label %inner.end -inner.catch: - call void @h(i32 %x) - unreachable -inner.end: - catchendpad unwind label %right.end -exit: - ret void -} -; In this case left and right are both parents of inner. This differs from -; @test1 in that inner is a catchpad rather than a cleanuppad, which makes -; inner.end a block that gets cloned so that left and right each contain a -; copy (catchendpad blocks are considered to be part of the parent funclet -; of the associated catchpad). The catchendpad in %inner.end unwinds to -; %right.end (which belongs to the entry funclet). -; CHECK-LABEL: define void @test2( -; CHECK: left: -; CHECK: cleanuppad -; CHECK: %x.for.left = call i32 @g() -; CHECK: invoke void @f() -; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]] -; CHECK: right: -; CHECK: to label %right.catch unwind label %[[RIGHT_END:.+]] -; CHECK: right.catch: -; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]] -; CHECK: [[RIGHT_END]]: -; CHECK: catchendpad unwind to caller -; CHECK: [[SHARED_CONT_RIGHT]]: -; CHECK: unreachable -; CHECK: [[SHARED_CONT_LEFT]]: -; CHECK: unreachable -; CHECK: [[INNER_RIGHT]]: -; CHECK: catchpad [] -; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]] -; CHECK: [[INNER_LEFT]]: -; CHECK: catchpad [] -; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]] -; CHECK: [[INNER_CATCH_RIGHT]]: -; CHECK: call void @h(i32 %x) -; CHECK: unreachable -; CHECK: [[INNER_CATCH_LEFT]]: -; CHECK: call void @h(i32 %x.for.left) -; CHECK: unreachable -; CHECK: [[INNER_END_LEFT]]: -; CHECK: catchendpad unwind to caller -; CHECK: [[INNER_END_RIGHT]]: -; CHECK: catchendpad unwind label %[[RIGHT_END]] - -define void @test3() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %exit unwind label %left -left: - %l = cleanuppad [] - br label %shared -left.end: - cleanupendpad %l unwind label %right -right: - catchpad [] - to label %right.catch unwind label %right.end -right.catch: - br label %shared -right.end: - catchendpad unwind to caller -shared: - %x = call i32 @g() - invoke void @f() - to label %shared.cont unwind label %inner -shared.cont: - unreachable -inner: - catchpad [] - to label %inner.catch unwind label %inner.end -inner.catch: - call void @h(i32 %x) - unreachable -inner.end: - catchendpad unwind label %left.end -exit: - ret void -} -; In this case, %left and %right are siblings with %entry as the parent of both, -; while %left and %right are both parents of %inner. The catchendpad in -; %inner.end unwinds to %left.end. When %inner is cloned a copy of %inner.end -; will be made for both %left and %right, but because %left.end is a cleanup pad -; and %right is a catch pad the unwind edge from the copy of %inner.end for -; %right must be removed. -; CHECK-LABEL: define void @test3( -; CHECK: left: -; CHECK: %l = cleanuppad [] -; CHECK: %x.for.left = call i32 @g() -; CHECK: invoke void @f() -; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]] -; CHECK: [[LEFT_END:left.end.*]]: -; CHECK: cleanupendpad %l unwind label %right -; CHECK: right: -; CHECK: to label %right.catch unwind label %[[RIGHT_END:.+]] -; CHECK: right.catch: -; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]] -; CHECK: [[RIGHT_END]]: -; CHECK: catchendpad unwind to caller -; CHECK: [[SHARED_CONT_RIGHT]]: -; CHECK: unreachable -; CHECK: [[SHARED_CONT_LEFT]]: -; CHECK: unreachable -; CHECK: [[INNER_RIGHT]]: -; CHECK: catchpad [] -; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]] -; CHECK: [[INNER_LEFT]]: -; CHECK: catchpad [] -; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]] -; CHECK: [[INNER_CATCH_RIGHT]]: -; CHECK: call void @h(i32 %x) -; CHECK: unreachable -; CHECK: [[INNER_CATCH_LEFT]]: -; CHECK: call void @h(i32 %x.for.left) -; CHECK: unreachable -; CHECK: [[INNER_END_LEFT]]: -; CHECK: catchendpad unwind label %[[LEFT_END]] -; CHECK: [[INNER_END_RIGHT]]: -; CHECK: catchendpad unwind to caller - - -define void @test4() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %exit unwind label %left -left: - catchpad [] - to label %left.catch unwind label %left.end -left.catch: - br label %shared -left.end: - catchendpad unwind label %right -right: - catchpad [] - to label %right.catch unwind label %right.end -right.catch: - br label %shared -right.end: - catchendpad unwind to caller -shared: - %x = call i32 @g() - invoke void @f() - to label %shared.cont unwind label %inner -shared.cont: - unreachable -inner: - catchpad [] - to label %inner.catch unwind label %inner.end -inner.catch: - call void @h(i32 %x) - unreachable -inner.end: - catchendpad unwind label %left.end -exit: - ret void -} -; This is a variation of @test3 in which both %left and %right are catch pads. -; In this case, %left and %right are siblings with %entry as the parent of both, -; while %left and %right are both parents of %inner. The catchendpad in -; %inner.end unwinds to %left.end. When %inner is cloned a copy of %inner.end -; will be made for both %left and %right, but because the catchpad in %right -; does not unwind to %left.end the unwind edge from the copy of %inner.end for -; %right must be removed. -; CHECK-LABEL: define void @test4( -; CHECK: left: -; CHECK: catchpad [] -; CHECK: to label %left.catch unwind label %[[LEFT_END:.+]] -; CHECK: left.catch: -; CHECK: %x.for.left = call i32 @g() -; CHECK: invoke void @f() -; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]] -; CHECK: [[LEFT_END]]: -; CHECK: catchendpad unwind label %right -; CHECK: right: -; CHECK: to label %right.catch unwind label %[[RIGHT_END:.+]] -; CHECK: right.catch: -; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]] -; CHECK: [[RIGHT_END]]: -; CHECK: catchendpad unwind to caller -; CHECK: [[SHARED_CONT_RIGHT]]: -; CHECK: unreachable -; CHECK: [[SHARED_CONT_LEFT]]: -; CHECK: unreachable -; CHECK: [[INNER_RIGHT]]: -; CHECK: catchpad [] -; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]] -; CHECK: [[INNER_LEFT]]: -; CHECK: catchpad [] -; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]] -; CHECK: [[INNER_CATCH_RIGHT]]: -; CHECK: call void @h(i32 %x) -; CHECK: unreachable -; CHECK: [[INNER_CATCH_LEFT]]: -; CHECK: call void @h(i32 %x.for.left) -; CHECK: unreachable -; CHECK: [[INNER_END_RIGHT]]: -; CHECK: catchendpad unwind to caller -; CHECK: [[INNER_END_LEFT]]: -; CHECK: catchendpad unwind label %[[LEFT_END]] - - -define void @test5() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %exit unwind label %left -left: - catchpad [] - to label %left.catch unwind label %left.end -left.catch: - br label %shared -left.end: - catchendpad unwind label %right -right: - %r = cleanuppad [] - br label %shared -shared: - %x = call i32 @g() - invoke void @f() - to label %shared.cont unwind label %inner -shared.cont: - unreachable -inner: - catchpad [] - to label %inner.catch unwind label %inner.end -inner.catch: - call void @h(i32 %x) - unreachable -inner.end: - catchendpad unwind label %left.end -exit: - ret void -} -; Like @test3, %left and %right are siblings with %entry as the parent of both, -; while %left and %right are both parents of %inner. This case makes %left a -; catch and %right a cleanup so that %inner unwinds to %left.end, which is a -; block in %entry. The %inner funclet is cloned for %left and %right, but the -; copy of %inner.end for %right must have its unwind edge removed because the -; catchendpad at %left.end is not compatible with %right. -; CHECK-LABEL: define void @test5( -; CHECK: left: -; CHECK: catchpad [] -; CHECK: to label %left.catch unwind label %[[LEFT_END:.+]] -; CHECK: left.catch: -; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]] -; CHECK: [[LEFT_END]]: -; CHECK: catchendpad unwind label %right -; CHECK: right: -; CHECK: %r = cleanuppad [] -; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]] -; CHECK: [[SHARED_CONT_RIGHT]]: -; CHECK: unreachable -; CHECK: [[SHARED_CONT_LEFT]]: -; CHECK: unreachable -; CHECK: [[INNER_RIGHT]]: -; CHECK: catchpad [] -; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]] -; CHECK: [[INNER_LEFT]]: -; CHECK: catchpad [] -; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]] -; CHECK: [[INNER_CATCH_RIGHT]]: -; CHECK: call void @h(i32 %x) -; CHECK: unreachable -; CHECK: [[INNER_CATCH_LEFT]]: -; CHECK: call void @h(i32 %x.for.left) -; CHECK: unreachable -; CHECK: [[INNER_END_RIGHT]]: -; CHECK: catchendpad unwind to caller -; CHECK: [[INNER_END_LEFT]]: -; CHECK: catchendpad unwind label %[[LEFT_END]] - -define void @test6() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %exit unwind label %left -left: - catchpad [] - to label %left.catch unwind label %left.end -left.catch: - br label %shared -left.end: - catchendpad unwind label %middle -middle: - %m = catchpad [] - to label %middle.catch unwind label %middle.end -middle.catch: - catchret %m to label %exit -middle.end: - catchendpad unwind label %right -right: - %r = cleanuppad [] - br label %shared -shared: - %x = call i32 @g() - invoke void @f() - to label %shared.cont unwind label %inner -shared.cont: - unreachable -inner: - catchpad [] - to label %inner.catch unwind label %inner.end -inner.catch: - call void @h(i32 %x) - unreachable -inner.end: - catchendpad unwind label %left.end -exit: - ret void -} -; This is like @test5 but it inserts another sibling between %left and %right. -; In this case %left, %middle and %right are all siblings, while %left and -; %right are both parents of %inner. This checks the proper handling of the -; catchendpad in %inner.end (which will be cloned so that %left and %right both -; have copies) unwinding to a catchendpad that unwinds to a sibling. -; CHECK-LABEL: define void @test6( -; CHECK: left: -; CHECK: catchpad [] -; CHECK: to label %left.catch unwind label %[[LEFT_END:.+]] -; CHECK: left.catch: -; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]] -; CHECK: [[LEFT_END]]: -; CHECK: catchendpad unwind label %middle -; CHECK: middle: -; CHECK: catchpad [] -; CHECK: to label %middle.catch unwind label %middle.end -; CHECK: middle.catch: -; CHECK: catchret %m to label %exit -; CHECK: middle.end: -; CHECK: catchendpad unwind label %right -; CHECK: right: -; CHECK: %r = cleanuppad [] -; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]] -; CHECK: [[SHARED_CONT_RIGHT]]: -; CHECK: unreachable -; CHECK: [[SHARED_CONT_LEFT]]: -; CHECK: unreachable -; CHECK: [[INNER_RIGHT]]: -; CHECK: catchpad [] -; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]] -; CHECK: [[INNER_LEFT]]: -; CHECK: catchpad [] -; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]] -; CHECK: [[INNER_CATCH_RIGHT]]: -; CHECK: call void @h(i32 %x) -; CHECK: unreachable -; CHECK: [[INNER_CATCH_LEFT]]: -; CHECK: call void @h(i32 %x.for.left) -; CHECK: unreachable -; CHECK: [[INNER_END_RIGHT]]: -; CHECK: catchendpad unwind to caller -; CHECK: [[INNER_END_LEFT]]: -; CHECK: catchendpad unwind label %[[LEFT_END]] - - -define void @test7() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %exit unwind label %left -left: - catchpad [] - to label %left.catch unwind label %left.end -left.catch: - br label %shared -left.end: - catchendpad unwind label %right -right: - %r = cleanuppad [] - br label %shared -shared: - %x = call i32 @g() - invoke void @f() - to label %shared.cont unwind label %inner -shared.cont: - unreachable -inner: - catchpad [] - to label %inner.catch unwind label %inner.end -inner.catch: - call void @h(i32 %x) - unreachable -inner.end: - catchendpad unwind label %inner.sibling -inner.sibling: - %is = cleanuppad [] - call void @h(i32 0) - cleanupret %is unwind label %left.end -exit: - ret void -} -; This is like @test5 but instead of unwinding to %left.end, the catchendpad -; in %inner.end unwinds to a sibling cleanup pad. Both %inner (along with its -; associated blocks) and %inner.sibling must be cloned for %left and %right. -; The clones of %inner will be identical, but the copy of %inner.sibling for -; %right must end with an unreachable instruction, because it cannot unwind to -; %left.end. -; CHECK-LABEL: define void @test7( -; CHECK: left: -; CHECK: catchpad [] -; CHECK: to label %left.catch unwind label %[[LEFT_END:.+]] -; CHECK: left.catch: -; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]] -; CHECK: [[LEFT_END]]: -; CHECK: catchendpad unwind label %[[RIGHT:.+]] -; CHECK: [[RIGHT]]: -; CHECK: [[R:\%.+]] = cleanuppad [] -; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]] -; CHECK: [[SHARED_CONT_RIGHT]]: -; CHECK: unreachable -; CHECK: [[SHARED_CONT_LEFT]]: -; CHECK: unreachable -; CHECK: [[INNER_RIGHT]]: -; CHECK: catchpad [] -; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]] -; CHECK: [[INNER_LEFT]]: -; CHECK: catchpad [] -; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]] -; CHECK: [[INNER_CATCH_RIGHT]]: -; CHECK: call void @h(i32 %x) -; CHECK: unreachable -; CHECK: [[INNER_CATCH_LEFT]]: -; CHECK: call void @h(i32 %x.for.left) -; CHECK: unreachable -; CHECK: [[INNER_END_RIGHT]]: -; CHECK: catchendpad unwind label %[[INNER_SIBLING_RIGHT:.+]] -; CHECK: [[INNER_END_LEFT]]: -; CHECK: catchendpad unwind label %[[INNER_SIBLING_LEFT:.+]] -; CHECK: [[INNER_SIBLING_RIGHT]] -; CHECK: [[IS_R:\%.+]] = cleanuppad [] -; CHECK: call void @h(i32 0) -; CHECK: unreachable -; CHECK: [[INNER_SIBLING_LEFT]] -; CHECK: [[IS_L:\%.+]] = cleanuppad [] -; CHECK: call void @h(i32 0) -; CHECK: cleanupret [[IS_L]] unwind label %[[LEFT_END]] - - -define void @test8() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %invoke.cont unwind label %left -invoke.cont: - invoke void @f() - to label %unreachable unwind label %right -left: - cleanuppad [] - invoke void @f() to label %unreachable unwind label %inner -right: - catchpad [] - to label %right.catch unwind label %right.end -right.catch: - invoke void @f() to label %unreachable unwind label %inner -right.end: - catchendpad unwind to caller -inner: - %i = cleanuppad [] - %x = call i32 @g() - call void @h(i32 %x) - cleanupret %i unwind label %right.end -unreachable: - unreachable -} -; Another case of a two-parent child (like @test1), this time -; with the join at the entry itself instead of following a -; non-pad join. -; CHECK-LABEL: define void @test8( -; CHECK: invoke.cont: -; CHECK: to label %[[UNREACHABLE_ENTRY:.+]] unwind label %right -; CHECK: left: -; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_LEFT:.+]] -; CHECK: right: -; CHECK: to label %right.catch unwind label %right.end -; CHECK: right.catch: -; CHECK: to label %unreachable unwind label %[[INNER_RIGHT:.+]] -; CHECK: right.end: -; CHECK: catchendpad unwind to caller -; CHECK: [[INNER_RIGHT]]: -; CHECK: [[I_R:\%.+]] = cleanuppad [] -; CHECK: [[X_R:\%.+]] = call i32 @g() -; CHECK: call void @h(i32 [[X_R]]) -; CHECK: cleanupret [[I_R]] unwind label %right.end -; CHECK: [[INNER_LEFT]]: -; CHECK: [[I_L:\%.+]] = cleanuppad [] -; CHECK: [[X_L:\%.+]] = call i32 @g() -; CHECK: call void @h(i32 [[X_L]]) -; CHECK: unreachable -; CHECK: unreachable: -; CHECK: unreachable -; CHECK: [[UNREACHABLE_LEFT]]: -; CHECK: unreachable -; CHECK: [[UNREACHABLE_ENTRY]]: -; CHECK: unreachable - - -define void @test9() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %invoke.cont unwind label %left -invoke.cont: - invoke void @f() - to label %unreachable unwind label %right -left: - cleanuppad [] - br label %shared -right: - catchpad [] - to label %right.catch unwind label %right.end -right.catch: - br label %shared -right.end: - catchendpad unwind to caller -shared: - invoke void @f() - to label %unreachable unwind label %inner -inner: - cleanuppad [] - invoke void @f() - to label %unreachable unwind label %inner.child -inner.child: - cleanuppad [] - %x = call i32 @g() - call void @h(i32 %x) - unreachable -unreachable: - unreachable -} -; %inner is a two-parent child which itself has a child; need -; to make two copies of both the %inner and %inner.child. -; CHECK-LABEL: define void @test9( -; CHECK: invoke.cont: -; CHECK: to label %[[UNREACHABLE_ENTRY:.+]] unwind label %right -; CHECK: left: -; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_LEFT:.+]] -; CHECK: right: -; CHECK: to label %right.catch unwind label %right.end -; CHECK: right.catch: -; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]] -; CHECK: right.end: -; CHECK: catchendpad unwind to caller -; CHECK: [[INNER_RIGHT]]: -; CHECK: to label %[[UNREACHABLE_INNER_RIGHT:.+]] unwind label %[[INNER_CHILD_RIGHT:.+]] -; CHECK: [[INNER_LEFT]]: -; CHECK: to label %[[UNREACHABLE_INNER_LEFT:.+]] unwind label %[[INNER_CHILD_LEFT:.+]] -; CHECK: [[INNER_CHILD_RIGHT]]: -; CHECK: [[TMP:\%.+]] = cleanuppad [] -; CHECK: [[X:\%.+]] = call i32 @g() -; CHECK: call void @h(i32 [[X]]) -; CHECK: unreachable -; CHECK: [[INNER_CHILD_LEFT]]: -; CHECK: [[TMP:\%.+]] = cleanuppad [] -; CHECK: [[X:\%.+]] = call i32 @g() -; CHECK: call void @h(i32 [[X]]) -; CHECK: unreachable -; CHECK: [[UNREACHABLE_INNER_RIGHT]]: -; CHECK: unreachable -; CHECK: [[UNREACHABLE_INNER_LEFT]]: -; CHECK: unreachable -; CHECK: [[UNREACHABLE_RIGHT]]: -; CHECK: unreachable -; CHECK: [[UNREACHABLE_LEFT]]: -; CHECK: unreachable -; CHECK: [[UNREACHABLE_ENTRY]]: -; CHECK: unreachable - - -define void @test10() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %invoke.cont unwind label %left -invoke.cont: - invoke void @f() - to label %unreachable unwind label %right -left: - cleanuppad [] - call void @h(i32 1) - invoke void @f() - to label %unreachable unwind label %right -right: - cleanuppad [] - call void @h(i32 2) - invoke void @f() - to label %unreachable unwind label %left -unreachable: - unreachable -} -; This is an irreducible loop with two funclets that enter each other; -; need to make two copies of each funclet (one a child of root, the -; other a child of the opposite funclet), but also make sure not to -; clone self-descendants (if we tried to do that we'd need to make an -; infinite number of them). Presumably if optimizations ever generated -; such a thing it would mean that one of the two cleanups was originally -; the parent of the other, but that we'd somehow lost track in the CFG -; of which was which along the way; generating each possibility lets -; whichever case was correct execute correctly. -; CHECK-LABEL: define void @test10( -; CHECK: entry: -; CHECK: to label %invoke.cont unwind label %[[LEFT:.+]] -; CHECK: invoke.cont: -; CHECK: to label %[[UNREACHABLE_ENTRY:.+]] unwind label %[[RIGHT:.+]] -; CHECK: [[LEFT_FROM_RIGHT:.+]]: -; CHECK: call void @h(i32 1) -; CHECK: call void @f() -; CHECK: unreachable -; CHECK: [[LEFT]]: -; CHECK: call void @h(i32 1) -; CHECK: invoke void @f() -; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[RIGHT_FROM_LEFT:.+]] -; CHECK: [[RIGHT]]: -; CHECK: call void @h(i32 2) -; CHECK: invoke void @f() -; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[LEFT_FROM_RIGHT]] -; CHECK: [[RIGHT_FROM_LEFT]]: -; CHECK: call void @h(i32 2) -; CHECK: call void @f() -; CHECK: unreachable -; CHECK: [[UNREACHABLE_RIGHT]]: -; CHECK: unreachable -; CHECK: [[UNREACHABLE_LEFT]]: -; CHECK: unreachable -; CHECK: [[UNREACHABLE_ENTRY]]: -; CHECK: unreachable - - -define void @test11() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %exit unwind label %left -left: - catchpad [] - to label %left.catch unwind label %left.sibling -left.catch: - br label %shared -left.sibling: - %ls = catchpad [] - to label %left.sibling.catch unwind label %left.end -left.sibling.catch: - catchret %ls to label %exit -left.end: - catchendpad unwind label %right -right: - catchpad [] - to label %right.catch unwind label %right.end -right.catch: - br label %shared -right.end: - catchendpad unwind to caller -shared: - %x = call i32 @g() - invoke void @f() - to label %shared.cont unwind label %inner -shared.cont: - unreachable -inner: - catchpad [] - to label %inner.catch unwind label %inner.end -inner.catch: - call void @h(i32 %x) - unreachable -inner.end: - catchendpad unwind label %left.end -exit: - ret void -} -; This is a variation of @test4 in which the shared child funclet unwinds to a -; catchend pad that is the unwind destination of %left.sibling rather than %left -; but is still a valid destination for %inner as reach from %left. -; When %inner is cloned a copy of %inner.end will be made for both %left and -; %right, but because the catchpad in %right does not unwind to %left.end the -; unwind edge from the copy of %inner.end for %right must be removed. -; CHECK-LABEL: define void @test11( -; CHECK: left: -; CHECK: catchpad [] -; CHECK: to label %left.catch unwind label %left.sibling -; CHECK: left.catch: -; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]] -; CHECK: left.sibling: -; CHECK: catchpad [] -; CHECK: to label %left.sibling.catch unwind label %[[LEFT_END:.+]] -; CHECK: [[LEFT_END]]: -; CHECK: catchendpad unwind label %right -; CHECK: right: -; CHECK: to label %right.catch unwind label %[[RIGHT_END:.+]] -; CHECK: right.catch: -; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]] -; CHECK: [[RIGHT_END]]: -; CHECK: catchendpad unwind to caller -; CHECK: [[SHARED_CONT_RIGHT]]: -; CHECK: unreachable -; CHECK: [[SHARED_CONT_LEFT]]: -; CHECK: unreachable -; CHECK: [[INNER_RIGHT]]: -; CHECK: catchpad [] -; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]] -; CHECK: [[INNER_LEFT]]: -; CHECK: catchpad [] -; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]] -; CHECK: [[INNER_CATCH_RIGHT]]: -; CHECK: call void @h(i32 %x) -; CHECK: unreachable -; CHECK: [[INNER_CATCH_LEFT]]: -; CHECK: call void @h(i32 %x.for.left) -; CHECK: unreachable -; CHECK: [[INNER_END_RIGHT]]: -; CHECK: catchendpad unwind to caller -; CHECK: [[INNER_END_LEFT]]: -; CHECK: catchendpad unwind label %[[LEFT_END]] - - -define void @test12() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %exit unwind label %left -left: - catchpad [] - to label %left.catch unwind label %right -left.catch: - br label %shared -right: - catchpad [] - to label %right.catch unwind label %right.end -right.catch: - br label %shared -right.end: - catchendpad unwind to caller -shared: - %x = call i32 @g() - invoke void @f() - to label %shared.cont unwind label %inner -shared.cont: - unreachable -inner: - catchpad [] - to label %inner.catch unwind label %inner.end -inner.catch: - call void @h(i32 %x) - unreachable -inner.end: - catchendpad unwind label %right.end -exit: - ret void -} -; In this case %left and %right are both parents of %inner, so %inner must be -; cloned but the catchendpad unwind target in %inner.end is valid for both -; parents, so the unwind edge should not be removed in either case. -; CHECK-LABEL: define void @test12( -; CHECK: left: -; CHECK: catchpad [] -; CHECK: to label %left.catch unwind label %right -; CHECK: left.catch: -; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]] -; CHECK: right: -; CHECK: to label %right.catch unwind label %[[RIGHT_END:.+]] -; CHECK: right.catch: -; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]] -; CHECK: [[RIGHT_END]]: -; CHECK: catchendpad unwind to caller -; CHECK: [[SHARED_CONT_RIGHT]]: -; CHECK: unreachable -; CHECK: [[SHARED_CONT_LEFT]]: -; CHECK: unreachable -; CHECK: [[INNER_RIGHT]]: -; CHECK: catchpad [] -; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]] -; CHECK: [[INNER_LEFT]]: -; CHECK: catchpad [] -; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]] -; CHECK: [[INNER_CATCH_RIGHT]]: -; CHECK: call void @h(i32 %x) -; CHECK: unreachable -; CHECK: [[INNER_CATCH_LEFT]]: -; CHECK: call void @h(i32 %x.for.left) -; CHECK: unreachable -; CHECK: [[INNER_END_RIGHT]]: -; CHECK: catchendpad unwind label %[[RIGHT_END]] -; CHECK: [[INNER_END_LEFT]]: -; CHECK: catchendpad unwind label %[[RIGHT_END]] - -define void @test13() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %invoke.cont unwind label %left -invoke.cont: - invoke void @f() - to label %exit unwind label %right -left: - %l = catchpad [] - to label %left.cont unwind label %left.end -left.cont: - invoke void @f() - to label %left.ret unwind label %inner -left.ret: - catchret %l to label %invoke.cont -left.end: - catchendpad unwind to caller -right: - %r = catchpad [] - to label %right.catch unwind label %right.end -right.catch: - invoke void @f() - to label %right.ret unwind label %inner -right.ret: - catchret %r to label %exit -right.end: - catchendpad unwind to caller -shared: - call void @h(i32 0) - unreachable -inner: - %i = catchpad [] - to label %inner.catch unwind label %inner.end -inner.catch: - call void @h(i32 1) - catchret %i to label %shared -inner.end: - catchendpad unwind label %left.end -exit: - ret void -} -; This case tests the scenario where a funclet with multiple parents uses a -; catchret to return to a block that may exist in either parent funclets. -; Both %left and %right are parents of %inner. During common block cloning -; a clone of %shared will be made so that both %left and %right have a copy, -; but the copy of %shared for one of the parent funclets will be unreachable -; until the %inner funclet is cloned. When the %inner.catch block is cloned -; during the %inner funclet cloning, the catchret instruction should be updated -; so that the catchret in the copy %inner.catch for %left returns to the copy of -; %shared in %left and the catchret in the copy of %inner.catch for %right -; returns to the copy of %shared for %right. -; CHECK-LABEL: define void @test13( -; CHECK: left: -; CHECK: %l = catchpad [] -; CHECK: to label %left.cont unwind label %left.end -; CHECK: left.cont: -; CHECK: invoke void @f() -; CHECK: to label %left.ret unwind label %[[INNER_LEFT:.+]] -; CHECK: left.ret: -; CHECK: catchret %l to label %invoke.cont -; CHECK: left.end: -; CHECK: catchendpad unwind to caller -; CHECK: right: -; CHECK: %r = catchpad [] -; CHECK: to label %right.catch unwind label %right.end -; CHECK: right.catch: -; CHECK: invoke void @f() -; CHECK: to label %right.ret unwind label %[[INNER_RIGHT:.+]] -; CHECK: right.ret: -; CHECK: catchret %r to label %exit -; CHECK: right.end: -; CHECK: catchendpad unwind to caller -; CHECK: [[SHARED_RIGHT:.+]]: -; CHECK: call void @h(i32 0) -; CHECK: unreachable -; CHECK: [[SHARED_LEFT:.+]]: -; CHECK: call void @h(i32 0) -; CHECK: unreachable -; CHECK: [[INNER_RIGHT]]: -; CHECK: %[[I_RIGHT:.+]] = catchpad [] -; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]] -; CHECK: [[INNER_LEFT]]: -; CHECK: %[[I_LEFT:.+]] = catchpad [] -; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]] -; CHECK: [[INNER_CATCH_RIGHT]]: -; CHECK: call void @h(i32 1) -; CHECK: catchret %[[I_RIGHT]] to label %[[SHARED_RIGHT]] -; CHECK: [[INNER_CATCH_LEFT]]: -; CHECK: call void @h(i32 1) -; CHECK: catchret %[[I_LEFT]] to label %[[SHARED_LEFT]] -; CHECK: [[INNER_END_LEFT]]: -; CHECK: catchendpad unwind label %[[LEFT_END]] -; CHECK: [[INNER_END_RIGHT]]: -; CHECK: catchendpad unwind to caller - - -define void @test14() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %exit unwind label %left -left: - %l = catchpad [] - to label %shared unwind label %left.end -left.cont: - invoke void @f() - to label %left.ret unwind label %right -left.ret: - catchret %l to label %exit -left.end: - catchendpad unwind to caller -right: - catchpad [] - to label %right.catch unwind label %right.end -right.catch: - br label %shared -right.end: - catchendpad unwind label %left.end -shared: - invoke void @f() - to label %shared.cont unwind label %inner -shared.cont: - unreachable -inner: - %i = catchpad [] - to label %inner.catch unwind label %inner.end -inner.catch: - call void @h(i32 0) - catchret %i to label %left.cont -inner.end: - catchendpad unwind label %left.end -exit: - ret void -} -; This case tests another scenario where a funclet with multiple parents uses a -; catchret to return to a block in one of the parent funclets. Here %right and -; %left are both parents of %inner and %left is a parent of %right. The -; catchret in %inner.catch will cause %left.cont and %left.ret to be cloned for -; both %left and %right, but the catchret in %left.ret is invalid for %right -; but the catchret instruction in the copy of %left.ret for %right will be -; removed as an implausible terminator. -; CHECK-LABEL: define void @test14( -; CHECK: left: -; CHECK: %l = catchpad [] -; CHECK: to label %[[SHARED_LEFT:.+]] unwind label %[[LEFT_END:.+]] -; CHECK: [[LEFT_CONT:left.cont.*]]: -; CHECK: invoke void @f() -; CHECK: to label %[[LEFT_RET:.+]] unwind label %[[RIGHT:.+]] -; CHECK: [[LEFT_RET]]: -; CHECK: catchret %l to label %exit -; CHECK: [[LEFT_END]]: -; CHECK: catchendpad unwind to caller -; CHECK: [[RIGHT]]: -; CHECK: catchpad [] -; CHECK: to label %[[RIGHT_CATCH:.+]] unwind label %[[RIGHT_END:.+]] -; CHECK: [[RIGHT_CATCH]]: -; CHECK: invoke void @f() -; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]] -; CHECK: [[RIGHT_END]]: -; CHECK: catchendpad unwind label %[[LEFT_END]] -; CHECK: [[SHARED_LEFT]]: -; CHECK: invoke void @f() -; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]] -; CHECK: [[SHARED_CONT_RIGHT]]: -; CHECK: unreachable -; CHECK: [[SHARED_CONT_LEFT]]: -; CHECK: unreachable -; CHECK: [[INNER_LEFT]]: -; CHECK: [[I_LEFT:\%.+]] = catchpad [] -; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]] -; CHECK: [[INNER_RIGHT]]: -; CHECK: [[I_RIGHT:\%.+]] = catchpad [] -; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]] -; CHECK: [[INNER_CATCH_LEFT]]: -; CHECK: call void @h(i32 0) -; CHECK: catchret [[I_LEFT]] to label %[[LEFT_CONT]] -; CHECK: [[INNER_CATCH_RIGHT]]: -; CHECK: call void @h(i32 0) -; CHECK: unreachable -; CHECK: [[INNER_END_LEFT]]: -; CHECK: catchendpad unwind label %[[LEFT_END]] -; CHECK: [[INNER_END_RIGHT]]: -; CHECK: catchendpad unwind to caller - -define void @test15() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %exit unwind label %left -left: - %l = catchpad [] - to label %left.catch unwind label %left.end -left.catch: - invoke void @f() - to label %shared unwind label %right -left.ret: - catchret %l to label %exit -left.end: - catchendpad unwind to caller -right: - catchpad [] - to label %right.catch unwind label %right.end -right.catch: - br label %shared -right.end: - catchendpad unwind label %left.end -shared: - invoke void @f() - to label %shared.cont unwind label %inner -shared.cont: - unreachable -inner: - %i = catchpad [] - to label %inner.catch unwind label %inner.end -inner.catch: - call void @h(i32 0) - catchret %i to label %left.ret -inner.end: - catchendpad unwind label %left.end -exit: - ret void -} -; This case is a variation of test14 but instead of returning to an invoke the -; catchret in %inner.catch returns to a catchret instruction. -; CHECK-LABEL: define void @test15( -; CHECK: left: -; CHECK: %l = catchpad [] -; CHECK: to label %left.catch unwind label %[[LEFT_END:.+]] -; CHECK: left.catch: -; CHECK: invoke void @f() -; CHECK: to label %[[SHARED_LEFT:.+]] unwind label %[[RIGHT:.+]] -; CHECK: [[LEFT_RET_RIGHT:.+]]: -; CHECK: unreachable -; CHECK: [[LEFT_RET_LEFT:.+]]: -; CHECK: catchret %l to label %exit -; CHECK: [[LEFT_END]]: -; CHECK: catchendpad unwind to caller -; CHECK: [[RIGHT]]: -; CHECK: catchpad [] -; CHECK: to label %[[RIGHT_CATCH:.+]] unwind label %[[RIGHT_END:.+]] -; CHECK: [[RIGHT_CATCH]]: -; CHECK: invoke void @f() -; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]] -; CHECK: [[RIGHT_END]]: -; CHECK: catchendpad unwind label %[[LEFT_END]] -; CHECK: [[SHARED_LEFT]]: -; CHECK: invoke void @f() -; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]] -; CHECK: [[SHARED_CONT_RIGHT]]: -; CHECK: unreachable -; CHECK: [[SHARED_CONT_LEFT]]: -; CHECK: unreachable -; CHECK: [[INNER_LEFT]]: -; CHECK: [[I_LEFT:\%.+]] = catchpad [] -; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]] -; CHECK: [[INNER_RIGHT]]: -; CHECK: [[I_RIGHT:\%.+]] = catchpad [] -; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]] -; CHECK: [[INNER_CATCH_LEFT]]: -; CHECK: call void @h(i32 0) -; CHECK: catchret [[I_LEFT]] to label %[[LEFT_RET_LEFT]] -; CHECK: [[INNER_CATCH_RIGHT]]: -; CHECK: call void @h(i32 0) -; CHECK: catchret [[I_RIGHT]] to label %[[LEFT_RET_RIGHT]] -; CHECK: [[INNER_END_RIGHT]]: -; CHECK: catchendpad unwind to caller -; CHECK: [[INNER_END_LEFT]]: -; CHECK: catchendpad unwind label %[[LEFT_END]] - - -define void @test16() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %exit unwind label %left -left: - %l = cleanuppad [] - br label %shared -left.cont: - cleanupret %l unwind label %right -left.end: - cleanupendpad %l unwind label %right -right: - catchpad [] - to label %right.catch unwind label %right.end -right.catch: - br label %shared -right.end: - catchendpad unwind to caller -shared: - invoke void @f() - to label %shared.cont unwind label %inner -shared.cont: - unreachable -inner: - %i = catchpad [] - to label %inner.catch unwind label %inner.end -inner.catch: - call void @h(i32 0) - catchret %i to label %left.cont -inner.end: - catchendpad unwind label %left.end -exit: - ret void -} -; This case is another variation of test14 but here the catchret in %inner.catch -; returns to a cleanupret instruction. -; CHECK-LABEL: define void @test16( -; CHECK: left: -; CHECK: %l = cleanuppad [] -; CHECK: invoke void @f() -; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]] -; CHECK: [[LEFT_CONT_RIGHT:.+]]: -; CHECK: unreachable -; CHECK: [[LEFT_CONT_LEFT:.+]]: -; CHECK: cleanupret %l unwind label %[[RIGHT:.+]] -; CHECK: [[LEFT_END_LEFT:.+]]: -; CHECK: cleanupendpad %l unwind label %[[RIGHT]] -; CHECK: [[RIGHT]]: -; CHECK: catchpad [] -; CHECK: to label %[[RIGHT_CATCH:.+]] unwind label %[[RIGHT_END:.+]] -; CHECK: [[RIGHT_CATCH]]: -; CHECK: invoke void @f() -; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]] -; CHECK: [[RIGHT_END]]: -; CHECK: catchendpad unwind to caller -; CHECK: [[SHARED_CONT_RIGHT]]: -; CHECK: unreachable -; CHECK: [[SHARED_CONT_LEFT]]: -; CHECK: unreachable -; CHECK: [[INNER_RIGHT]]: -; CHECK: [[I_RIGHT:\%.+]] = catchpad [] -; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]] -; CHECK: [[INNER_LEFT]]: -; CHECK: [[I_LEFT:\%.+]] = catchpad [] -; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]] -; CHECK: [[INNER_CATCH_RIGHT]]: -; CHECK: call void @h(i32 0) -; CHECK: catchret [[I_RIGHT]] to label %[[LEFT_CONT_RIGHT]] -; CHECK: [[INNER_CATCH_LEFT]]: -; CHECK: call void @h(i32 0) -; CHECK: catchret [[I_LEFT]] to label %[[LEFT_CONT_LEFT]] -; CHECK: [[INNER_END_LEFT]]: -; CHECK: catchendpad unwind label %[[LEFT_END_LEFT]] -; CHECK: [[INNER_END_RIGHT]]: -; CHECK: catchendpad unwind to caller - - -define void @test17() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %invoke.cont unwind label %left -invoke.cont: - invoke void @f() - to label %exit unwind label %right -left: - %l = cleanuppad [] - br label %shared -right: - catchpad [] - to label %right.catch unwind label %right.end -right.catch: - br label %shared -right.end: - catchendpad unwind to caller -shared: - invoke void @f() - to label %unreachable unwind label %inner -unreachable: - unreachable -inner: - %i = catchpad [] - to label %inner.catch unwind label %inner.sibling -inner.catch: - call void @h(i32 0) - unreachable -inner.sibling: - %is = catchpad [] - to label %inner.sibling.catch unwind label %inner.end -inner.sibling.catch: - invoke void @f() - to label %unreachable unwind label %inner.end -inner.end: - catchendpad unwind label %right.end -exit: - ret void -} -; This case tests the scenario where two catchpads with the same catchendpad -; have multiple parents. Both %left and %right are parents of %inner and -; %inner.sibling so both of the inner funclets must be cloned. Because -; the catchendpad in %inner.end unwinds to the catchendpad for %right, the -; unwind edge should be removed for the copy of %inner.end that is reached -; from %left. In addition, the %inner.siblin.catch block contains an invoke -; that unwinds to the shared inner catchendpad. The unwind destination for -; this invoke should be updated to unwind to the correct cloned %inner.end -; for each path to the funclet. -; CHECK-LABEL: define void @test17( -; CHECK: left: -; CHECK: %l = cleanuppad [] -; CHECK: invoke void @f() -; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]] -; CHECK: right: -; CHECK: catchpad [] -; CHECK: to label %[[RIGHT_CATCH:.+]] unwind label %[[RIGHT_END:.+]] -; CHECK: [[RIGHT_CATCH]]: -; CHECK: invoke void @f() -; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]] -; CHECK: [[RIGHT_END]]: -; CHECK: catchendpad unwind to caller -; CHECK: [[SHARED_CONT_RIGHT]]: -; CHECK: unreachable -; CHECK: [[SHARED_CONT_LEFT]]: -; CHECK: unreachable -; CHECK: [[INNER_RIGHT]]: -; CHECK: [[I_RIGHT:\%.+]] = catchpad [] -; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_SIBLING_RIGHT:.+]] -; CHECK: [[INNER_LEFT]]: -; CHECK: [[I_LEFT:\%.+]] = catchpad [] -; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_SIBLING_LEFT:.+]] -; CHECK: [[INNER_CATCH_RIGHT]]: -; CHECK: call void @h(i32 0) -; CHECK: unreachable -; CHECK: [[INNER_CATCH_LEFT]]: -; CHECK: call void @h(i32 0) -; CHECK: unreachable -; CHECK: [[INNER_SIBLING_RIGHT]]: -; CHECK: [[IS_RIGHT:\%.+]] = catchpad [] -; CHECK: to label %[[INNER_SIBLING_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]] -; CHECK: [[INNER_SIBLING_LEFT]]: -; CHECK: [[IS_LEFT:\%.+]] = catchpad [] -; CHECK: to label %[[INNER_SIBLING_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]] -; CHECK: [[INNER_SIBLING_CATCH_RIGHT]]: -; CHECK: invoke void @f() -; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[INNER_END_RIGHT]] -; CHECK: [[INNER_SIBLING_CATCH_LEFT]]: -; CHECK: invoke void @f() -; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_END_LEFT]] -; CHECK: [[INNER_END_LEFT]]: -; CHECK: catchendpad unwind to caller -; CHECK: [[INNER_END_RIGHT]]: -; CHECK: catchendpad unwind label %[[RIGHT_END]] - - -define void @test18() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %invoke.cont unwind label %left -invoke.cont: - invoke void @f() - to label %exit unwind label %right -left: - %l = cleanuppad [] - br label %shared -right: - catchpad [] - to label %right.catch unwind label %right.end -right.catch: - br label %shared -right.end: - catchendpad unwind to caller -shared: - invoke void @f() - to label %unreachable unwind label %inner -unreachable: - unreachable -inner: - %i = catchpad [] - to label %inner.catch unwind label %inner.sibling -inner.catch: - invoke void @f() - to label %unreachable unwind label %inner.end -inner.sibling: - %is = catchpad [] - to label %inner.sibling.catch unwind label %inner.end -inner.sibling.catch: - call void @h(i32 0) - unreachable -inner.end: - catchendpad unwind label %right.end -exit: - ret void -} -; This is like test17 except that the inner invoke is moved from the -; %inner.sibling funclet to %inner so that it is unwinding to a -; catchendpad block that has not yet been cloned. The unwind destination -; of the invoke should still be updated to reach the correct copy of -; %inner.end for the path by which it is reached. -; CHECK-LABEL: define void @test18( -; CHECK: left: -; CHECK: %l = cleanuppad [] -; CHECK: invoke void @f() -; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]] -; CHECK: right: -; CHECK: catchpad [] -; CHECK: to label %[[RIGHT_CATCH:.+]] unwind label %[[RIGHT_END:.+]] -; CHECK: [[RIGHT_CATCH]]: -; CHECK: invoke void @f() -; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]] -; CHECK: [[RIGHT_END]]: -; CHECK: catchendpad unwind to caller -; CHECK: [[SHARED_CONT_RIGHT]]: -; CHECK: unreachable -; CHECK: [[SHARED_CONT_LEFT]]: -; CHECK: unreachable -; CHECK: [[INNER_RIGHT]]: -; CHECK: [[I_RIGHT:\%.+]] = catchpad [] -; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_SIBLING_RIGHT:.+]] -; CHECK: [[INNER_LEFT]]: -; CHECK: [[I_LEFT:\%.+]] = catchpad [] -; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_SIBLING_LEFT:.+]] -; CHECK: [[INNER_CATCH_RIGHT]]: -; CHECK: invoke void @f() -; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]] -; CHECK: [[INNER_CATCH_LEFT]]: -; CHECK: invoke void @f() -; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]] -; CHECK: [[INNER_SIBLING_RIGHT]]: -; CHECK: [[IS_RIGHT:\%.+]] = catchpad [] -; CHECK: to label %[[INNER_SIBLING_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT]] -; CHECK: [[INNER_SIBLING_LEFT]]: -; CHECK: [[IS_LEFT:\%.+]] = catchpad [] -; CHECK: to label %[[INNER_SIBLING_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT]] -; CHECK: [[INNER_SIBLING_CATCH_RIGHT]]: -; CHECK: call void @h(i32 0) -; CHECK: unreachable -; CHECK: [[INNER_SIBLING_CATCH_LEFT]]: -; CHECK: call void @h(i32 0) -; CHECK: unreachable -; CHECK: [[INNER_END_LEFT]]: -; CHECK: catchendpad unwind to caller -; CHECK: [[INNER_END_RIGHT]]: -; CHECK: catchendpad unwind label %[[RIGHT_END]] - - -define void @test19() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %invoke.cont unwind label %left -invoke.cont: - invoke void @f() - to label %exit unwind label %right -left: - %l = cleanuppad [] - br label %shared -right: - catchpad [] - to label %right.catch unwind label %right.end -right.catch: - br label %shared -right.end: - catchendpad unwind to caller -shared: - invoke void @f() - to label %unreachable unwind label %inner -unreachable: - unreachable -inner: - %i = cleanuppad [] - invoke void @f() - to label %unreachable unwind label %inner.end -inner.end: - cleanupendpad %i unwind label %right.end -exit: - ret void -} -; This case tests the scenario where an invoke in a funclet with multiple -; parents unwinds to a cleanup end pad for the funclet. The unwind destination -; for the invoke should map to the correct copy of the cleanup end pad block. -; CHECK-LABEL: define void @test19( -; CHECK: left: -; CHECK: %l = cleanuppad [] -; CHECK: invoke void @f() -; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]] -; CHECK: right: -; CHECK: catchpad [] -; CHECK: to label %[[RIGHT_CATCH:.+]] unwind label %[[RIGHT_END:.+]] -; CHECK: [[RIGHT_CATCH]]: -; CHECK: invoke void @f() -; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]] -; CHECK: [[RIGHT_END]]: -; CHECK: catchendpad unwind to caller -; CHECK: [[SHARED_CONT_RIGHT]]: -; CHECK: unreachable -; CHECK: [[SHARED_CONT_LEFT]]: -; CHECK: unreachable -; CHECK: [[INNER_RIGHT]]: -; CHECK: [[I_RIGHT:\%.+]] = cleanuppad [] -; CHECK: invoke void @f() -; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]] -; CHECK: [[INNER_LEFT]]: -; CHECK: [[I_LEFT:\%.+]] = cleanuppad [] -; CHECK: invoke void @f() -; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]] -; CHECK: [[INNER_END_RIGHT]]: -; CHECK: cleanupendpad [[I_RIGHT]] unwind label %[[RIGHT_END]] -; CHECK: [[INNER_END_LEFT]]: -; CHECK: cleanupendpad [[I_LEFT]] unwind to caller - -define void @test20() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %invoke.cont unwind label %left -invoke.cont: - invoke void @f() - to label %exit unwind label %right -left: - %l = cleanuppad [] - br label %shared -right: - catchpad [] - to label %right.catch unwind label %right.end -right.catch: - br label %shared -right.end: - catchendpad unwind to caller -shared: - invoke void @f() - to label %unreachable unwind label %inner -unreachable: - unreachable -inner: - %i = cleanuppad [] - invoke void @f() - to label %unreachable unwind label %inner.cleanup -inner.cleanup: - cleanuppad [] - call void @f() - unreachable -exit: - ret void -} -; This tests the case where a funclet with multiple parents contains an invoke -; instruction that unwinds to a child funclet. Here %left and %right are both -; parents of %inner. Initially %inner is the only parent of %inner.cleanup but -; after %inner is cloned, %inner.cleanup has multiple parents and so it must -; also be cloned. -; CHECK-LABEL: define void @test20( -; CHECK: left: -; CHECK: %l = cleanuppad [] -; CHECK: invoke void @f() -; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]] -; CHECK: right: -; CHECK: catchpad [] -; CHECK: to label %[[RIGHT_CATCH:.+]] unwind label %[[RIGHT_END:.+]] -; CHECK: [[RIGHT_CATCH]]: -; CHECK: invoke void @f() -; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]] -; CHECK: [[RIGHT_END]]: -; CHECK: catchendpad unwind to caller -; CHECK: [[SHARED_CONT_RIGHT]]: -; CHECK: unreachable -; CHECK: [[SHARED_CONT_LEFT]]: -; CHECK: unreachable -; CHECK: [[INNER_RIGHT]]: -; CHECK: [[I_RIGHT:\%.+]] = cleanuppad [] -; CHECK: invoke void @f() -; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[INNER_CLEANUP_RIGHT:.+]] -; CHECK: [[INNER_LEFT]]: -; CHECK: [[I_LEFT:\%.+]] = cleanuppad [] -; CHECK: invoke void @f() -; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_CLEANUP_LEFT:.+]] -; CHECK: [[INNER_CLEANUP_RIGHT]]: -; CHECK: cleanuppad [] -; CHECK: call void @f() -; CHECK: unreachable -; CHECK: [[INNER_CLEANUP_LEFT]]: -; CHECK: cleanuppad [] -; CHECK: call void @f() -; CHECK: unreachable - - Index: test/CodeGen/WinEH/wineh-no-demotion.ll =================================================================== --- test/CodeGen/WinEH/wineh-no-demotion.ll +++ test/CodeGen/WinEH/wineh-no-demotion.ll @@ -2,6 +2,8 @@ declare i32 @__CxxFrameHandler3(...) +declare i32 @__C_specific_handler(...) + declare void @f() declare i32 @g() @@ -9,7 +11,7 @@ declare 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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() Index: test/CodeGen/WinEH/wineh-statenumbering-cleanups.ll =================================================================== --- test/CodeGen/WinEH/wineh-statenumbering-cleanups.ll +++ test/CodeGen/WinEH/wineh-statenumbering-cleanups.ll @@ -7,38 +7,6 @@ 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 @@ 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 @@ ;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 } Index: test/CodeGen/WinEH/wineh-statenumbering.ll =================================================================== --- test/CodeGen/WinEH/wineh-statenumbering.ll +++ test/CodeGen/WinEH/wineh-statenumbering.ll @@ -37,9 +37,10 @@ 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 @@ to label %unreachable unwind label %catch.dispatch.1 catch.dispatch.1: ; preds = %catch - %2 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch.3 unwind label %catchendblock.2 - + %cs2 = catchswitch within %1 [label %catch.3] unwind to caller catch.3: ; preds = %catch.dispatch.1 + %2 = catchpad within %cs2 [i8* null, i32 u0x40, i8* null] ; CHECK: catch.3: ; CHECK: store i32 3 - ; CHECK: invoke void @g(i32 1) - invoke void @g(i32 1) - to label %invoke.cont unwind label %catchendblock.2 - -invoke.cont: ; preds = %catch.3 - catchret %2 to label %try.cont + ; CHECK: call void @g(i32 1) + call void @g(i32 1) + catchret from %2 to label %try.cont -try.cont: ; preds = %invoke.cont +try.cont: ; preds = %catch.3 ; CHECK: try.cont: ; CHECK: store i32 1 - ; CHECK: invoke void @g(i32 2) - invoke void @g(i32 2) - to label %invoke.cont.4 unwind label %catchendblock - -invoke.cont.4: ; preds = %try.cont + ; CHECK: call void @g(i32 2) + call void @g(i32 2) unreachable -catchendblock.2: ; preds = %catch.3, %catch.dispatch.1 - catchendpad unwind label %catchendblock - -catchendblock: ; preds = %catchendblock.2, %try.cont, %catch.dispatch - catchendpad unwind to caller - unreachable: ; preds = %catch unreachable Index: test/CodeGen/X86/branchfolding-catchpads.ll =================================================================== --- test/CodeGen/X86/branchfolding-catchpads.ll +++ test/CodeGen/X86/branchfolding-catchpads.ll @@ -19,24 +19,18 @@ 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 @@ 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 ] Index: test/CodeGen/X86/catchpad-realign-savexmm.ll =================================================================== --- test/CodeGen/X86/catchpad-realign-savexmm.ll +++ test/CodeGen/X86/catchpad-realign-savexmm.ll @@ -14,19 +14,17 @@ %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 Index: test/CodeGen/X86/catchpad-regmask.ll =================================================================== --- test/CodeGen/X86/catchpad-regmask.ll +++ test/CodeGen/X86/catchpad-regmask.ll @@ -41,14 +41,14 @@ 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 @@ 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 @@ 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 } Index: test/CodeGen/X86/catchpad-weight.ll =================================================================== --- test/CodeGen/X86/catchpad-weight.ll +++ test/CodeGen/X86/catchpad-weight.ll @@ -2,7 +2,7 @@ ; Check if the edge weight to the catchpad is calculated correctly. -; CHECK: Successors according to CFG: BB#3(0x7ffff100 / 0x80000000 = 100.00%) BB#1(0x00000800 / 0x80000000 = 0.00%) BB#4(0x00000400 / 0x80000000 = 0.00%) BB#6(0x00000200 / 0x80000000 = 0.00%) BB#8(0x00000100 / 0x80000000 = 0.00%) +; CHECK: Successors according to CFG: BB#2(0x7ffff100 / 0x80000000 = 100.00%) BB#1(0x00000800 / 0x80000000 = 0.00%) BB#3(0x00000400 / 0x80000000 = 0.00%) BB#4(0x00000200 / 0x80000000 = 0.00%) BB#5(0x00000100 / 0x80000000 = 0.00%) target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64--windows-msvc18.0.0" @@ -31,11 +31,11 @@ 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 @@ 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 Index: test/CodeGen/X86/catchret-empty-fallthrough.ll =================================================================== --- test/CodeGen/X86/catchret-empty-fallthrough.ll +++ test/CodeGen/X86/catchret-empty-fallthrough.ll @@ -19,14 +19,11 @@ 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 Index: test/CodeGen/X86/catchret-fallthrough.ll =================================================================== --- test/CodeGen/X86/catchret-fallthrough.ll +++ test/CodeGen/X86/catchret-fallthrough.ll @@ -18,14 +18,11 @@ 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 Index: test/CodeGen/X86/cleanuppad-inalloca.ll =================================================================== --- test/CodeGen/X86/cleanuppad-inalloca.ll +++ test/CodeGen/X86/cleanuppad-inalloca.ll @@ -29,9 +29,9 @@ 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: Index: test/CodeGen/X86/cleanuppad-large-codemodel.ll =================================================================== --- test/CodeGen/X86/cleanuppad-large-codemodel.ll +++ test/CodeGen/X86/cleanuppad-large-codemodel.ll @@ -9,9 +9,9 @@ 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 } Index: test/CodeGen/X86/cleanuppad-realign.ll =================================================================== --- test/CodeGen/X86/cleanuppad-realign.ll +++ test/CodeGen/X86/cleanuppad-realign.ll @@ -17,9 +17,9 @@ 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 Index: test/CodeGen/X86/funclet-layout.ll =================================================================== --- test/CodeGen/X86/funclet-layout.ll +++ test/CodeGen/X86/funclet-layout.ll @@ -15,21 +15,21 @@ 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 @@ 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 @@ 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 @@ ; 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 Index: test/CodeGen/X86/late-address-taken.ll =================================================================== --- test/CodeGen/X86/late-address-taken.ll +++ test/CodeGen/X86/late-address-taken.ll @@ -22,19 +22,17 @@ 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 Index: test/CodeGen/X86/seh-catch-all-win32.ll =================================================================== --- test/CodeGen/X86/seh-catch-all-win32.ll +++ test/CodeGen/X86/seh-catch-all-win32.ll @@ -22,16 +22,13 @@ 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 @@ ; 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 Index: test/CodeGen/X86/seh-catch-all.ll =================================================================== --- test/CodeGen/X86/seh-catch-all.ll +++ test/CodeGen/X86/seh-catch-all.ll @@ -16,16 +16,13 @@ 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 @@ ; 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 Index: test/CodeGen/X86/seh-catchpad.ll =================================================================== --- test/CodeGen/X86/seh-catchpad.ll +++ test/CodeGen/X86/seh-catchpad.ll @@ -45,13 +45,6 @@ %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 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 @@ __try.cont.12: ; preds = %invoke.cont.3, %entry, %__except.9 ret i32 0 -catchendblock.8: ; preds = %catch.dispatch.7 - catchendpad unwind to caller +catch.dispatch: ; preds = %entry + %cs1 = catchswitch within none [label %__except] unwind label %catch.dispatch.7 + +__except: ; preds = %catch.dispatch + %cp1 = catchpad within %cs1 [i8* null] + catchret from %cp1 to label %__except.2 -ehcleanup.end: ; preds = %ehcleanup - cleanupendpad %1 unwind label %catch.dispatch.7 +ehcleanup: ; preds = %__except.2 + %cp2 = cleanuppad within none [] + invoke fastcc void @"\01?fin$0@0@main@@"() #4 + to label %invoke.cont.6 unwind label %catch.dispatch.7 + +invoke.cont.6: ; preds = %ehcleanup + cleanupret from %cp2 unwind label %catch.dispatch.7 + +catch.dispatch.7: + %cs2 = catchswitch within none [label %__except.ret] unwind to caller + +__except.ret: ; preds = %catch.dispatch.7 + %cp3 = catchpad within %cs2 [i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@main@@" to i8*)] + catchret from %cp3 to label %__except.9 } ; CHECK: main: # @main @@ -112,7 +103,7 @@ ; 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 @@ ; 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 @@ ; 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) Index: test/CodeGen/X86/seh-except-finally.ll =================================================================== --- test/CodeGen/X86/seh-except-finally.ll +++ test/CodeGen/X86/seh-except-finally.ll @@ -49,37 +49,24 @@ 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: Index: test/CodeGen/X86/seh-exception-code.ll =================================================================== --- test/CodeGen/X86/seh-exception-code.ll +++ test/CodeGen/X86/seh-exception-code.ll @@ -14,11 +14,11 @@ 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 @@ __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 Index: test/CodeGen/X86/seh-finally.ll =================================================================== --- test/CodeGen/X86/seh-finally.ll +++ test/CodeGen/X86/seh-finally.ll @@ -17,15 +17,9 @@ 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: Index: test/CodeGen/X86/seh-safe-div-win32.ll =================================================================== --- test/CodeGen/X86/seh-safe-div-win32.ll +++ test/CodeGen/X86/seh-safe-div-win32.ll @@ -31,28 +31,22 @@ 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 @@ ; 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 @@ ; 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: Index: test/CodeGen/X86/seh-safe-div.ll =================================================================== --- test/CodeGen/X86/seh-safe-div.ll +++ test/CodeGen/X86/seh-safe-div.ll @@ -30,28 +30,22 @@ 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 @@ ; 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 @@ ; 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 Index: test/CodeGen/X86/seh-stack-realign.ll =================================================================== --- test/CodeGen/X86/seh-stack-realign.ll +++ test/CodeGen/X86/seh-stack-realign.ll @@ -23,16 +23,13 @@ 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 @@ ; 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 Index: test/CodeGen/X86/tail-dup-catchret.ll =================================================================== --- test/CodeGen/X86/tail-dup-catchret.ll +++ test/CodeGen/X86/tail-dup-catchret.ll @@ -8,19 +8,16 @@ 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: Index: test/CodeGen/X86/tail-merge-wineh.ll =================================================================== --- test/CodeGen/X86/tail-merge-wineh.ll +++ test/CodeGen/X86/tail-merge-wineh.ll @@ -54,11 +54,11 @@ 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 @@ 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 @@ 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 @@ 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 } Index: test/CodeGen/X86/win-catchpad-csrs.ll =================================================================== --- test/CodeGen/X86/win-catchpad-csrs.ll +++ test/CodeGen/X86/win-catchpad-csrs.ll @@ -16,7 +16,7 @@ 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 @@ 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 @@ ; 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 @@ ; 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 @@ 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 @@ ; 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 @@ 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 @@ ; 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 Index: test/CodeGen/X86/win-catchpad-nested-cxx.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/win-catchpad-nested-cxx.ll @@ -0,0 +1,105 @@ +; RUN: llc -verify-machineinstrs -mtriple=i686-pc-windows-msvc < %s \ +; RUN: | FileCheck --check-prefix=CHECK --check-prefix=X86 %s +; RUN: llc -verify-machineinstrs -mtriple=x86_64-pc-windows-msvc < %s \ +; RUN: | FileCheck --check-prefix=CHECK --check-prefix=X64 %s + +; Loosely based on IR for this C++ source code: +; void f(int p); +; void try_in_catch() { +; try { +; f(1); +; } catch (...) { +; try { +; f(2); +; } catch (...) { +; f(3); +; } +; } +; } + +declare void @f(i32 %p) +declare i32 @__CxxFrameHandler3(...) + +define i32 @try_in_catch() personality i32 (...)* @__CxxFrameHandler3 { +entry: + invoke void @f(i32 1) + to label %try.cont unwind label %catch.dispatch.1 +try.cont: + ret i32 0 + +catch.dispatch.1: + %cs1 = catchswitch within none [label %handler1] unwind to caller +handler1: + %h1 = catchpad within %cs1 [i8* null, i32 64, i8* null] + invoke void @f(i32 2) + to label %catchret1 unwind label %catch.dispatch.2 +catchret1: + catchret from %h1 to label %try.cont + +catch.dispatch.2: + %cs2 = catchswitch within %h1 [label %handler2] unwind to caller +handler2: + %h2 = catchpad within %cs2 [i8* null, i32 64, i8* null] + call void @f(i32 3) + catchret from %h2 to label %catchret1 +} + +; X86-LABEL: L__ehtable$try_in_catch: +; X64-LABEL: $cppxdata$try_in_catch: +; CHECK-NEXT: .long 429065506 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long ($stateUnwindMap$try_in_catch) +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long ($tryMap$try_in_catch) +; ip2state num + ptr +; X86-NEXT: .long 0 +; X86-NEXT: .long 0 +; X64-NEXT: .long 7 +; X64-NEXT: .long ($ip2state$try_in_catch) +; unwindhelp offset +; X64-NEXT: .long 40 +; CHECK-NEXT: .long 0 +; EHFlags +; CHECK-NEXT: .long 1 + +; CHECK: $tryMap$try_in_catch: +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long ($handlerMap$0$try_in_catch) +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long ($handlerMap$1$try_in_catch) + +; CHECK: $handlerMap$0$try_in_catch: +; CHECK-NEXT: .long 64 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long "?catch${{[0-9]+}}@?0?try_in_catch@4HA" +; X64-NEXT: .long 56 + +; CHECK: $handlerMap$1$try_in_catch: +; CHECK-NEXT: .long 64 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long "?catch${{[0-9]+}}@?0?try_in_catch@4HA" +; X64-NEXT: .long 56 + +; X64: $ip2state$try_in_catch: +; X64-NEXT: .long .Lfunc_begin0@IMGREL +; X64-NEXT: .long -1 +; X64-NEXT: .long .Ltmp0@IMGREL+1 +; X64-NEXT: .long 0 +; X64-NEXT: .long .Ltmp1@IMGREL+1 +; X64-NEXT: .long -1 +; X64-NEXT: .long "?catch$2@?0?try_in_catch@4HA"@IMGREL +; X64-NEXT: .long 1 +; X64-NEXT: .long .Ltmp2@IMGREL+1 +; X64-NEXT: .long 2 +; X64-NEXT: .long .Ltmp3@IMGREL+1 +; X64-NEXT: .long 1 +; X64-NEXT: .long "?catch$4@?0?try_in_catch@4HA"@IMGREL +; X64-NEXT: .long 3 Index: test/CodeGen/X86/win-catchpad-nested.ll =================================================================== --- test/CodeGen/X86/win-catchpad-nested.ll +++ test/CodeGen/X86/win-catchpad-nested.ll @@ -7,26 +7,25 @@ define void @test1() personality void ()* @ProcessCLRException { entry: invoke void @f() - to label %exit unwind label %outer.pad -outer.pad: - %outer = catchpad [i32 1] - to label %outer.catch unwind label %outer.end + to label %exit unwind label %catch.dispatch.1 +exit: + ret void + +catch.dispatch.1: + %cs1 = catchswitch within none [label %outer.catch] unwind to caller + outer.catch: + %cp1 = catchpad within %cs1 [i32 1] invoke void @f() - to label %outer.ret unwind label %inner.pad -inner.pad: - %inner = catchpad [i32 2] - to label %inner.ret unwind label %inner.end -inner.ret: - catchret %inner to label %outer.ret -inner.end: - catchendpad unwind label %outer.end + to label %outer.ret unwind label %catch.dispatch.2 outer.ret: - catchret %outer to label %exit -outer.end: - catchendpad unwind to caller -exit: - ret void + catchret from %cp1 to label %exit + +catch.dispatch.2: + %cs2 = catchswitch within %cp1 [label %inner.catch] unwind to caller +inner.catch: + %cp2 = catchpad within %cs2 [i32 2] + catchret from %cp2 to label %outer.ret } ; Check the catchret targets @@ -37,7 +36,7 @@ ; 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 Index: test/CodeGen/X86/win-catchpad-varargs.ll =================================================================== --- test/CodeGen/X86/win-catchpad-varargs.ll +++ test/CodeGen/X86/win-catchpad-varargs.ll @@ -13,20 +13,17 @@ 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 ] Index: test/CodeGen/X86/win-catchpad.ll =================================================================== --- test/CodeGen/X86/win-catchpad.ll +++ test/CodeGen/X86/win-catchpad.ll @@ -28,7 +28,7 @@ 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 @@ 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 Index: test/CodeGen/X86/win-cleanuppad.ll =================================================================== --- test/CodeGen/X86/win-cleanuppad.ll +++ test/CodeGen/X86/win-cleanuppad.ll @@ -14,9 +14,9 @@ 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 @@ 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: Index: test/CodeGen/X86/win-funclet-cfi.ll =================================================================== --- test/CodeGen/X86/win-funclet-cfi.ll +++ test/CodeGen/X86/win-funclet-cfi.ll @@ -9,24 +9,21 @@ 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 @@ ; 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) Index: test/CodeGen/X86/win-mixed-ehpersonality.ll =================================================================== --- test/CodeGen/X86/win-mixed-ehpersonality.ll +++ test/CodeGen/X86/win-mixed-ehpersonality.ll @@ -18,12 +18,10 @@ 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 @@ ; CHECK: xorl %eax, %eax ; CHECK: .LBB0_[[epilogue:[0-9]+]] ; CHECK: retq -; CHECK: # %lpad +; CHECK: # %catch{{$}} ; CHECK: movl $1, %eax ; CHECK: jmp .LBB0_[[epilogue]] Index: test/CodeGen/X86/win32-eh-states.ll =================================================================== --- test/CodeGen/X86/win32-eh-states.ll +++ test/CodeGen/X86/win32-eh-states.ll @@ -1,4 +1,5 @@ -; RUN: llc -mtriple=i686-pc-windows-msvc < %s | FileCheck %s +; RUN: llc -mtriple=i686-pc-windows-msvc < %s | FileCheck %s --check-prefix=X86 +; RUN: llc -mtriple=x86_64-pc-windows-msvc < %s | FileCheck %s --check-prefix=X64 ; Based on this source: ; extern "C" void may_throw(int); @@ -40,59 +41,167 @@ to label %try.cont.9 unwind label %lpad try.cont.9: ; preds = %invoke.cont.3, %invoke.cont, %catch.7 - ; FIXME: Something about our CFG breaks TailDuplication. This empy asm blocks - ; it so we can focus on testing the state numbering. - call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"() ret void lpad: ; preds = %catch, %entry - %p1 = catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null] - to label %catch unwind label %end.inner.catch + %cs1 = catchswitch within none [label %catch] unwind label %lpad.1 catch: ; preds = %lpad.1 + %p1 = catchpad within %cs1 [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null] invoke void @may_throw(i32 3) - to label %invoke.cont.3 unwind label %end.inner.catch + to label %invoke.cont.3 unwind label %lpad.1 invoke.cont.3: ; preds = %catch - catchret %p1 to label %try.cont.9 - - -end.inner.catch: - catchendpad unwind label %lpad.1 + catchret from %p1 to label %try.cont.9 lpad.1: ; preds = %invoke.cont - %p2 = catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null] - to label %catch.7 unwind label %eh.resume + %cs2 = catchswitch within none [label %catch.7] unwind to caller catch.7: - invoke void @may_throw(i32 4) - to label %invoke.cont.10 unwind label %eh.resume + %p2 = catchpad within %cs2 [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null] + call void @may_throw(i32 4) + catchret from %p2 to label %try.cont.9 +} + +; X86-LABEL: _f: +; X86: movl $-1, [[state:[-0-9]+]](%ebp) +; X86: movl $___ehhandler$f, {{.*}} +; +; X86: movl $0, [[state]](%ebp) +; X86: movl $1, (%esp) +; X86: calll _may_throw +; +; X86: movl $1, [[state]](%ebp) +; X86: movl $2, (%esp) +; X86: calll _may_throw +; +; X86: movl $2, [[state]](%ebp) +; X86: movl $3, (%esp) +; X86: calll _may_throw +; +; X86: movl $3, [[state]](%ebp) +; X86: movl $4, (%esp) +; X86: calll _may_throw + + +; X64-LABEL: f: +; X64-LABEL: $ip2state$f: +; X64-NEXT: .long .Lfunc_begin0@IMGREL +; X64-NEXT: .long -1 +; X64-NEXT: .long .Ltmp{{.*}}@IMGREL+1 +; X64-NEXT: .long 0 +; X64-NEXT: .long .Ltmp{{.*}}@IMGREL+1 +; X64-NEXT: .long 1 +; X64-NEXT: .long .Ltmp{{.*}}@IMGREL+1 +; X64-NEXT: .long -1 +; X64-NEXT: .long "?catch${{.*}}@?0?f@4HA"@IMGREL +; X64-NEXT: .long 2 +; X64-NEXT: .long "?catch${{.*}}@?0?f@4HA"@IMGREL +; X64-NEXT: .long 3 + +; Based on this source: +; extern "C" void may_throw(int); +; struct S { ~S(); }; +; void g() { +; S x; +; try { +; may_throw(-1); +; } catch (...) { +; may_throw(0); +; { +; S y; +; may_throw(1); +; } +; may_throw(2); +; } +; } -invoke.cont.10: - catchret %p2 to label %try.cont.9 +%struct.S = type { i8 } +declare void @"\01??1S@@QEAA@XZ"(%struct.S*) -eh.resume: ; preds = %catch.dispatch.4 - catchendpad unwind to caller +define void @g() personality i32 (...)* @__CxxFrameHandler3 { +entry: + %x = alloca %struct.S, align 1 + %y = alloca %struct.S, align 1 + invoke void @may_throw(i32 -1) + to label %unreachable unwind label %catch.dispatch + +catch.dispatch: ; preds = %entry + %0 = catchswitch within none [label %catch] unwind label %ehcleanup5 + +catch: ; preds = %catch.dispatch + %1 = catchpad within %0 [i8* null, i32 64, i8* null] + invoke void @may_throw(i32 0) + to label %invoke.cont unwind label %ehcleanup5 + +invoke.cont: ; preds = %catch + invoke void @may_throw(i32 1) + to label %invoke.cont2 unwind label %ehcleanup + +invoke.cont2: ; preds = %invoke.cont + invoke void @"\01??1S@@QEAA@XZ"(%struct.S* nonnull %y) + to label %invoke.cont3 unwind label %ehcleanup5 + +invoke.cont3: ; preds = %invoke.cont2 + invoke void @may_throw(i32 2) + to label %invoke.cont4 unwind label %ehcleanup5 + +invoke.cont4: ; preds = %invoke.cont3 + catchret from %1 to label %try.cont + +try.cont: ; preds = %invoke.cont4 + call void @"\01??1S@@QEAA@XZ"(%struct.S* nonnull %x) + ret void + +ehcleanup: ; preds = %invoke.cont + %2 = cleanuppad within %1 [] + call void @"\01??1S@@QEAA@XZ"(%struct.S* nonnull %y) + cleanupret from %2 unwind label %ehcleanup5 + +ehcleanup5: ; preds = %invoke.cont2, %invoke.cont3, %ehcleanup, %catch, %catch.dispatch + %3 = cleanuppad within none [] + call void @"\01??1S@@QEAA@XZ"(%struct.S* nonnull %x) + cleanupret from %3 unwind to caller + +unreachable: ; preds = %entry + unreachable } -; CHECK-LABEL: _f: -; CHECK: movl $-1, [[state:[-0-9]+]](%ebp) -; CHECK: movl $___ehhandler$f, {{.*}} +; X86-LABEL: _g: +; X86: movl $-1, [[state:[-0-9]+]](%ebp) +; X86: movl $___ehhandler$g, {{.*}} ; -; CHECK: movl $0, [[state]](%ebp) -; CHECK: movl $1, (%esp) -; CHECK: calll _may_throw +; X86: movl $1, [[state]](%ebp) +; X86: movl $-1, (%esp) +; X86: calll _may_throw ; -; CHECK: movl $1, [[state]](%ebp) -; CHECK: movl $2, (%esp) -; CHECK: calll _may_throw +; X86: movl $2, [[state]](%ebp) +; X86: movl $0, (%esp) +; X86: calll _may_throw ; -; CHECK: movl $2, [[state]](%ebp) -; CHECK: movl $3, (%esp) -; CHECK: calll _may_throw +; X86: movl $3, [[state]](%ebp) +; X86: movl $1, (%esp) +; X86: calll _may_throw ; -; CHECK: movl $3, [[state]](%ebp) -; CHECK: movl $4, (%esp) -; CHECK: calll _may_throw - -; CHECK: .safeseh ___ehhandler$f +; X86: movl $2, [[state]](%ebp) +; X86: movl $2, (%esp) +; X86: calll _may_throw + +; X64-LABEL: g: +; X64-LABEL: $ip2state$g: +; X64-NEXT: .long .Lfunc_begin1@IMGREL +; X64-NEXT: .long -1 +; X64-NEXT: .long .Ltmp{{.*}}@IMGREL+1 +; X64-NEXT: .long 1 +; X64-NEXT: .long .Ltmp{{.*}}@IMGREL+1 +; X64-NEXT: .long -1 +; X64-NEXT: .long "?catch${{.*}}@?0?g@4HA"@IMGREL +; X64-NEXT: .long 2 +; X64-NEXT: .long .Ltmp{{.*}}@IMGREL+1 +; X64-NEXT: .long 3 +; X64-NEXT: .long .Ltmp{{.*}}@IMGREL+1 +; X64-NEXT: .long 2 + + +; X86: .safeseh ___ehhandler$f +; X86: .safeseh ___ehhandler$g Index: test/CodeGen/X86/win32-eh.ll =================================================================== --- test/CodeGen/X86/win32-eh.ll +++ test/CodeGen/X86/win32-eh.ll @@ -19,12 +19,10 @@ 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 @@ ; 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 @@ 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 @@ ; 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 @@ 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: Index: test/CodeGen/X86/win32-seh-catchpad-realign.ll =================================================================== --- test/CodeGen/X86/win32-seh-catchpad-realign.ll +++ test/CodeGen/X86/win32-seh-catchpad-realign.ll @@ -15,17 +15,14 @@ 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 @@ ; 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. Index: test/CodeGen/X86/win32-seh-catchpad.ll =================================================================== --- test/CodeGen/X86/win32-seh-catchpad.ll +++ test/CodeGen/X86/win32-seh-catchpad.ll @@ -11,10 +11,11 @@ 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 @@ 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 @@ 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 @@ ; CHECK: .long -1 ; CHECK: .long _nested_exceptions_filter_catchall ; CHECK: .long LBB -; CHECK: .long -1 +; CHECK: .long 0 ; CHECK: .long _nested_exceptions_filter_catchall ; CHECK: .long LBB -; CHECK: .long -1 +; CHECK: .long 1 ; CHECK: .long _nested_exceptions_filter_catchall ; CHECK: .long LBB -; CHECK: .long 2 +; CHECK: .long 1 ; CHECK: .long _nested_exceptions_filter_catchall ; CHECK: .long LBB -; CHECK: .long 3 +; CHECK: .long -1 ; CHECK: .long _nested_exceptions_filter_catchall ; CHECK: .long LBB -; CHECK: .long 3 +; CHECK: .long -1 ; CHECK: .long _nested_exceptions_filter_catchall ; CHECK: .long LBB @@ -203,21 +189,19 @@ 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) Index: test/CodeGen/X86/win32-seh-nested-finally.ll =================================================================== --- test/CodeGen/X86/win32-seh-nested-finally.ll +++ test/CodeGen/X86/win32-seh-nested-finally.ll @@ -17,26 +17,17 @@ 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 Index: test/CodeGen/X86/wineh-coreclr.ll =================================================================== --- test/CodeGen/X86/wineh-coreclr.ll +++ test/CodeGen/X86/wineh-coreclr.ll @@ -13,7 +13,7 @@ ; f(2); ; } catch (type1) { ; f(3); -; } catch (type2) [ +; } catch (type2) { ; f(4); ; try { ; f(5); @@ -50,10 +50,10 @@ 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 @@ ; 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 @@ ; 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 @@ 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 @@ ; 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 @@ ; 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) Index: test/CodeGen/X86/wineh-exceptionpointer.ll =================================================================== --- test/CodeGen/X86/wineh-exceptionpointer.ll +++ test/CodeGen/X86/wineh-exceptionpointer.ll @@ -11,18 +11,16 @@ 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 } Index: test/Feature/exception.ll =================================================================== --- test/Feature/exception.ll +++ test/Feature/exception.ll @@ -31,8 +31,8 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 } Index: test/Transforms/CodeGenPrepare/catchpad-phi-cast.ll =================================================================== --- test/Transforms/CodeGenPrepare/catchpad-phi-cast.ll +++ test/Transforms/CodeGenPrepare/catchpad-phi-cast.ll @@ -18,9 +18,6 @@ ; 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 @@ ; 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 @@ ret void catch1: - %cp1 = catchpad [] to label %catch.dispatch unwind label %catchend1 + %cs1 = catchswitch within none [label %handler1] unwind to caller -catch2: - %cp2 = catchpad [] to label %catch.dispatch unwind label %catchend2 +handler1: + %cp1 = catchpad within %cs1 [] + br label %catch.shared +; CHECK: handler1: +; CHECK-NEXT: catchpad within %cs1 +; CHECK: %[[p1:[0-9]+]] = bitcast i32* %x to i8* -; CHECK: catch.dispatch: -; CHECK-NEXT: %p = phi i8* [ %p1, %catch1 ], [ %p2, %catch2 ] -catch.dispatch: - %p = phi i8* [ %p1, %catch1 ], [ %p2, %catch2 ] +catch2: + %cs2 = catchswitch within none [label %handler2] unwind to caller + +handler2: + %cp2 = catchpad within %cs2 [] + br label %catch.shared +; CHECK: handler2: +; CHECK: catchpad within %cs2 +; CHECK: %[[p2:[0-9]+]] = bitcast i32* %y to i8* + +; CHECK: catch.shared: +; CHECK-NEXT: %p = phi i8* [ %[[p1]], %handler1 ], [ %[[p2]], %handler2 ] +catch.shared: + %p = phi i8* [ %p1, %handler1 ], [ %p2, %handler2 ] call void @g(i8* %p) unreachable - -catchend1: - catchendpad unwind to caller - -catchend2: - catchendpad unwind to caller } ; CodeGenPrepare will want to hoist these llvm.dbg.value calls to the phi, but @@ -75,24 +79,22 @@ 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} Index: test/Transforms/GVN/funclet.ll =================================================================== --- test/Transforms/GVN/funclet.ll +++ test/Transforms/GVN/funclet.ll @@ -17,12 +17,12 @@ 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 @@ %add = add i8 %load_b, %load_c ret i8 %add -catchendblock: ; preds = %catch.dispatch - catchendpad unwind to caller - unreachable: ; preds = %entry unreachable } Index: test/Transforms/GVN/pre-load.ll =================================================================== --- test/Transforms/GVN/pre-load.ll +++ test/Transforms/GVN/pre-load.ll @@ -399,7 +399,7 @@ ; 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 @@ 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 } Index: test/Transforms/Inline/PR25155.ll =================================================================== --- test/Transforms/Inline/PR25155.ll +++ test/Transforms/Inline/PR25155.ll @@ -8,21 +8,23 @@ 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 @@ ; 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 @@ ret void terminate: ; preds = %entry - terminatepad [void ()* @terminate] unwind to caller + terminatepad within none [void ()* @terminate] unwind to caller } declare void @g() Index: test/Transforms/InstCombine/token.ll =================================================================== --- test/Transforms/InstCombine/token.ll +++ test/Transforms/InstCombine/token.ll @@ -9,14 +9,14 @@ 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 @@ 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 @@ 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( Index: test/Transforms/LoopStrengthReduce/funclet.ll =================================================================== --- test/Transforms/LoopStrengthReduce/funclet.ll +++ test/Transforms/LoopStrengthReduce/funclet.ll @@ -20,19 +20,17 @@ 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 @@ 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 @@ 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 @@ ; 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 @@ 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 @@ ; 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 @@ 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 @@ 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 ] Index: test/Transforms/LoopStrengthReduce/pr25541.ll =================================================================== --- test/Transforms/LoopStrengthReduce/pr25541.ll +++ test/Transforms/LoopStrengthReduce/pr25541.ll @@ -12,10 +12,10 @@ 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 @@ 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 Index: test/Transforms/LoopUnswitch/cleanuppad.ll =================================================================== --- /dev/null +++ test/Transforms/LoopUnswitch/cleanuppad.ll @@ -0,0 +1,44 @@ +; RUN: opt -S -loop-unswitch < %s | FileCheck %s +target triple = "x86_64-pc-win32" + +define void @f(i32 %doit, i1 %x, i1 %y) personality i32 (...)* @__CxxFrameHandler3 { +entry: + %tobool = icmp eq i32 %doit, 0 + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + br i1 %x, label %for.body, label %for.end + +for.body: ; preds = %for.cond + br i1 %tobool, label %if.then, label %for.inc + +if.then: ; preds = %for.body + br i1 %y, label %for.inc, label %delete.notnull + +delete.notnull: ; preds = %if.then + invoke void @g() + to label %invoke.cont unwind label %lpad + +invoke.cont: ; preds = %delete.notnull + br label %for.inc + +lpad: ; preds = %delete.notnull + %cp = cleanuppad within none [] + cleanupret from %cp unwind to caller + +for.inc: ; preds = %invoke.cont, %if.then, %for.body + br label %for.cond + +for.end: ; preds = %for.cond + ret void +} + +declare void @g() + +declare i32 @__CxxFrameHandler3(...) + +; CHECK-LABEL: define void @f( +; CHECK: cleanuppad within none [] +; CHECK-NOT: cleanuppad + +attributes #0 = { ssp uwtable } Index: test/Transforms/SimplifyCFG/empty-cleanuppad.ll =================================================================== --- test/Transforms/SimplifyCFG/empty-cleanuppad.ll +++ test/Transforms/SimplifyCFG/empty-cleanuppad.ll @@ -31,12 +31,12 @@ ret void ehcleanup: ; preds = %entry - %0 = cleanuppad [] - cleanupret %0 unwind label %ehcleanup.1 + %0 = cleanuppad within none [] + cleanupret from %0 unwind label %ehcleanup.1 ehcleanup.1: ; preds = %ehcleanup - %1 = cleanuppad [] - cleanupret %1 unwind to caller + %1 = cleanuppad within none [] + cleanupret from %1 unwind to caller } @@ -60,15 +60,14 @@ ; CHECK: entry: ; CHECK: invoke void @g() ; CHECK: ehcleanup: -; CHECK: cleanuppad +; CHECK: cleanuppad within none ; CHECK: call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %b) -; CHECK: cleanupret %0 unwind label %catch.dispatch +; CHECK: cleanupret from %0 unwind label %catch.dispatch ; CHECK: catch.dispatch: -; CHECK: catchpad +; CHECK: catchswitch within none [label %catch] unwind to caller ; CHECK: catch: +; CHECK: catchpad ; CHECK: catchret -; CHECK: catchendblock: ; preds = %catch.dispatch -; CHECK: catchendpad unwind to caller ; CHECK-NOT: cleanuppad ; CHECK: } ; @@ -81,15 +80,16 @@ br label %try.cont ehcleanup: ; preds = %entry - %0 = cleanuppad [] + %0 = cleanuppad within none [] call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %b) - cleanupret %0 unwind label %catch.dispatch + cleanupret from %0 unwind label %catch.dispatch catch.dispatch: ; preds = %ehcleanup - %1 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock + %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup.1 catch: ; preds = %catch.dispatch - catchret %1 to label %catchret.dest + %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null] + catchret from %1 to label %catchret.dest catchret.dest: ; preds = %catch br label %try.cont @@ -97,12 +97,9 @@ try.cont: ; preds = %catchret.dest, %invoke.cont ret void -catchendblock: ; preds = %catch.dispatch - catchendpad unwind label %ehcleanup.1 - -ehcleanup.1: ; preds = %catchendblock - %2 = cleanuppad [] - cleanupret %2 unwind to caller +ehcleanup.1: + %2 = cleanuppad within none [] + cleanupret from %2 unwind to caller } @@ -121,21 +118,19 @@ ; In this case the inner cleanup pad should be eliminated and the invoke of g() ; should unwind directly to the catchpad. ; -; CHECK: define void @f3() +; CHECK-LABEL: define void @f3() ; CHECK: entry: ; CHECK: invoke void @g() ; CHECK: to label %try.cont unwind label %catch.dispatch ; CHECK: catch.dispatch: -; CHECK: catchpad [i8* null, i32 64, i8* null] -; CHECK-NEXT: to label %catch unwind label %catchendblock +; CHECK-NEXT: catchswitch within none [label %catch] unwind label %ehcleanup.1 ; CHECK: catch: +; CHECK: catchpad within %cs1 [i8* null, i32 64, i8* null] ; CHECK: catchret -; CHECK: catchendblock: -; CHECK: catchendpad unwind label %ehcleanup.1 ; CHECK: ehcleanup.1: ; CHECK: cleanuppad ; CHECK: call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a) -; CHECK: cleanupret %1 unwind to caller +; CHECK: cleanupret from %cp3 unwind to caller ; CHECK: } ; define void @f3() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { @@ -147,14 +142,15 @@ br label %try.cont ehcleanup: ; preds = %entry - %0 = cleanuppad [] - cleanupret %0 unwind label %catch.dispatch + %0 = cleanuppad within none [] + cleanupret from %0 unwind label %catch.dispatch catch.dispatch: ; preds = %ehcleanup - %1 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock + %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup.1 catch: ; preds = %catch.dispatch - catchret %1 to label %catchret.dest + %cp2 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null] + catchret from %cp2 to label %catchret.dest catchret.dest: ; preds = %catch br label %try.cont @@ -162,13 +158,10 @@ try.cont: ; preds = %catchret.dest, %invoke.cont ret void -catchendblock: ; preds = %catch.dispatch - catchendpad unwind label %ehcleanup.1 - -ehcleanup.1: ; preds = %catchendblock - %2 = cleanuppad [] +ehcleanup.1: + %cp3 = cleanuppad within none [] call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a) - cleanupret %2 unwind to caller + cleanupret from %cp3 unwind to caller } @@ -184,11 +177,10 @@ ; } ; ; In this case, the cleanuppad should be eliminated, the invoke outside of the -; call block should be converted to a call and the catchendpad should unwind -; to the caller (that is, that is, exception handling continues with the parent -; frame of the caller).) +; catch block should be converted to a call (that is, that is, exception +; handling continues with the parent frame of the caller).) ; -; CHECK: define void @f4() +; CHECK-LABEL: define void @f4() ; CHECK: entry: ; CHECK: call void @g ; Note: The cleanuppad simplification will insert an unconditional branch here @@ -196,11 +188,10 @@ ; CHECK: invoke void @g() ; CHECK: to label %try.cont unwind label %catch.dispatch ; CHECK: catch.dispatch: -; CHECK: catchpad +; CHECK: catchswitch within none [label %catch] unwind to caller ; CHECK: catch: +; CHECK: catchpad ; CHECK: catchret -; CHECK: catchendblock: -; CHECK: catchendpad unwind to caller ; CHECK-NOT: cleanuppad ; CHECK: } ; @@ -214,43 +205,41 @@ to label %try.cont unwind label %catch.dispatch catch.dispatch: ; preds = %invoke.cont - %0 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock + %cs1 = catchswitch within none [label %catch] unwind label %ehcleanup catch: ; preds = %catch.dispatch - catchret %0 to label %try.cont + %0 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null] + catchret from %0 to label %try.cont try.cont: ; preds = %catch, %invoke.cont ret void -catchendblock: ; preds = %catch.dispatch - catchendpad unwind label %ehcleanup - -ehcleanup: ; preds = %catchendblock, %entry - %1 = cleanuppad [] - cleanupret %1 unwind to caller +ehcleanup: + %cp2 = cleanuppad within none [] + cleanupret from %cp2 unwind to caller } ; This tests the case where a terminatepad unwinds to a cleanuppad. ; I'm not sure how this case would arise, but it seems to be syntactically ; legal so I'm testing it. ; -; CHECK: define void @f5() +; CHECK-LABEL: define void @f5() ; CHECK: entry: ; CHECK: invoke void @g() ; CHECK: to label %try.cont unwind label %terminate ; CHECK: terminate: -; CHECK: terminatepad [i7 4] unwind to caller +; CHECK: terminatepad within none [i7 4] unwind to caller ; CHECK-NOT: cleanuppad ; CHECK: try.cont: ; CHECK: invoke void @g() ; CHECK: to label %try.cont.1 unwind label %terminate.1 ; CHECK: terminate.1: -; CHECK: terminatepad [i7 4] unwind label %ehcleanup.2 +; CHECK: terminatepad within none [i7 4] unwind label %ehcleanup.2 ; CHECK-NOT: ehcleanup.1: ; CHECK: ehcleanup.2: ; CHECK: [[TMP:\%.+]] = cleanuppad ; CHECK: call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a) -; CHECK: cleanupret [[TMP]] unwind to caller +; CHECK: cleanupret from [[TMP]] unwind to caller ; CHECK: } define void @f5() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { entry: @@ -259,27 +248,27 @@ to label %try.cont unwind label %terminate terminate: ; preds = %entry - terminatepad [i7 4] unwind label %ehcleanup + terminatepad within none [i7 4] unwind label %ehcleanup ehcleanup: ; preds = %terminate - %0 = cleanuppad [] - cleanupret %0 unwind to caller + %0 = cleanuppad within none [] + cleanupret from %0 unwind to caller try.cont: ; preds = %entry invoke void @g() to label %try.cont.1 unwind label %terminate.1 terminate.1: ; preds = %try.cont - terminatepad [i7 4] unwind label %ehcleanup.1 + terminatepad within none [i7 4] unwind label %ehcleanup.1 ehcleanup.1: ; preds = %terminate.1 - %1 = cleanuppad [] - cleanupret %1 unwind label %ehcleanup.2 + %1 = cleanuppad within none [] + cleanupret from %1 unwind label %ehcleanup.2 ehcleanup.2: ; preds = %ehcleanup.1 - %2 = cleanuppad [] + %2 = cleanuppad within none [] call void @"\01??1S2@@QEAA@XZ"(%struct.S2* %a) - cleanupret %2 unwind to caller + cleanupret from %2 unwind to caller try.cont.1: ; preds = %try.cont ret void @@ -304,7 +293,7 @@ ; In this case, the cleanup pad should be eliminated and the PHI node in the ; cleanup pad should be sunk into the catch dispatch block. ; -; CHECK: define i32 @f6() +; CHECK-LABEL: define i32 @f6() ; CHECK: entry: ; CHECK: invoke void @g() ; CHECK: invoke.cont: @@ -325,17 +314,15 @@ ehcleanup: ; preds = %invoke.cont, %entry %state.0 = phi i32 [ 2, %invoke.cont ], [ 1, %entry ] - %0 = cleanuppad [] - cleanupret %0 unwind label %catch.dispatch + %0 = cleanuppad within none [] + cleanupret from %0 unwind label %catch.dispatch catch.dispatch: ; preds = %ehcleanup - %1 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock + %cs1 = catchswitch within none [label %catch] unwind to caller catch: ; preds = %catch.dispatch - catchret %1 to label %return - -catchendblock: ; preds = %catch.dispatch - catchendpad unwind to caller + %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null] + catchret from %1 to label %return return: ; preds = %invoke.cont, %catch %retval.0 = phi i32 [ %state.0, %catch ], [ 0, %invoke.cont ] @@ -363,7 +350,7 @@ ; In this case, the cleanup pad should be eliminated and the PHI node in the ; cleanup pad should be merged with the PHI node in the catch dispatch block. ; -; CHECK: define i32 @f7() +; CHECK-LABEL: define i32 @f7() ; CHECK: entry: ; CHECK: invoke void @g() ; CHECK: invoke.cont: @@ -390,18 +377,16 @@ ehcleanup: ; preds = %invoke.cont.1, %invoke.cont %state.0 = phi i32 [ 3, %invoke.cont.1 ], [ 2, %invoke.cont ] - %0 = cleanuppad [] - cleanupret %0 unwind label %catch.dispatch + %0 = cleanuppad within none [] + cleanupret from %0 unwind label %catch.dispatch catch.dispatch: ; preds = %ehcleanup, %entry %state.1 = phi i32 [ %state.0, %ehcleanup ], [ 1, %entry ] - %1 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock + %cs1 = catchswitch within none [label %catch] unwind to caller catch: ; preds = %catch.dispatch - catchret %1 to label %return - -catchendblock: ; preds = %catch.dispatch - catchendpad unwind to caller + %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null] + catchret from %1 to label %return return: ; preds = %invoke.cont.1, %catch %retval.0 = phi i32 [ %state.1, %catch ], [ 0, %invoke.cont.1 ] @@ -435,7 +420,7 @@ ; should have an incoming value entry for path from 'foo' that references the ; PHI node itself. ; -; CHECK: define void @f8() +; CHECK-LABEL: define void @f8() ; CHECK: entry: ; CHECK: invoke void @g() ; CHECK: invoke.cont: @@ -456,18 +441,16 @@ ehcleanup: ; preds = %invoke.cont, %entry %x = phi i32 [ 2, %invoke.cont ], [ 1, %entry ] - %0 = cleanuppad [] - cleanupret %0 unwind label %catch.dispatch + %0 = cleanuppad within none [] + cleanupret from %0 unwind label %catch.dispatch catch.dispatch: ; preds = %ehcleanup, %catch.cont - %1 = catchpad [i8* null, i32 u0x40, i8* null] to label %catch unwind label %catchendblock + %cs1 = catchswitch within none [label %catch] unwind to caller catch: ; preds = %catch.dispatch + %1 = catchpad within %cs1 [i8* null, i32 u0x40, i8* null] call void @use_x(i32 %x) - catchret %1 to label %catch.cont - -catchendblock: ; preds = %catch.dispatch - catchendpad unwind to caller + catchret from %1 to label %catch.cont catch.cont: ; preds = %catch invoke void @g() Index: test/Transforms/SimplifyCFG/wineh-unreachable.ll =================================================================== --- test/Transforms/SimplifyCFG/wineh-unreachable.ll +++ test/Transforms/SimplifyCFG/wineh-unreachable.ll @@ -12,7 +12,7 @@ exit: ret void unreachable.unwind: - cleanuppad [] + cleanuppad within none [] unreachable } @@ -22,24 +22,21 @@ invoke void @f() to label %exit unwind label %catch.pad catch.pad: - ; CHECK: catchpad [] - ; CHECK-NEXT: to label %catch.body unwind label %catch.end - %catch = catchpad [] - to label %catch.body unwind label %catch.end + %cs1 = catchswitch within none [label %catch.body] unwind label %unreachable.unwind + ; CHECK: catch.pad: + ; CHECK-NEXT: catchswitch within none [label %catch.body] unwind to caller catch.body: ; CHECK: catch.body: + ; CHECK-NEXT: catchpad within %cs1 ; CHECK-NEXT: call void @f() ; CHECK-NEXT: unreachable + %catch = catchpad within %cs1 [] call void @f() - catchret %catch to label %unreachable -catch.end: - ; CHECK: catch.end: - ; CHECK-NEXT: catchendpad unwind to caller - catchendpad unwind label %unreachable.unwind + catchret from %catch to label %unreachable exit: ret void unreachable.unwind: - cleanuppad [] + cleanuppad within none [] unreachable unreachable: unreachable @@ -51,24 +48,20 @@ invoke void @f() to label %exit unwind label %cleanup.pad cleanup.pad: - ; CHECK: %cleanup = cleanuppad [] + ; CHECK: %cleanup = cleanuppad within none [] ; CHECK-NEXT: call void @f() ; CHECK-NEXT: unreachable - %cleanup = cleanuppad [] + %cleanup = cleanuppad within none [] invoke void @f() - to label %cleanup.ret unwind label %cleanup.end + to label %cleanup.ret unwind label %unreachable.unwind cleanup.ret: ; This cleanupret should be rewritten to unreachable, ; and merged into the pred block. - cleanupret %cleanup unwind label %unreachable.unwind -cleanup.end: - ; This cleanupendpad should be rewritten to unreachable, - ; causing the invoke to be rewritten to a call. - cleanupendpad %cleanup unwind label %unreachable.unwind + cleanupret from %cleanup unwind label %unreachable.unwind exit: ret void unreachable.unwind: - cleanuppad [] + cleanuppad within none [] unreachable } @@ -78,12 +71,12 @@ invoke void @f() to label %exit unwind label %terminate.pad terminate.pad: - ; CHECK: terminatepad [] unwind to caller - terminatepad [] unwind label %unreachable.unwind + ; CHECK: terminatepad within none [] unwind to caller + terminatepad within none [] unwind label %unreachable.unwind exit: ret void unreachable.unwind: - cleanuppad [] + cleanuppad within none [] unreachable } @@ -94,14 +87,11 @@ to label %exit unwind label %catch.pad catch.pad: - %catch = catchpad [] - to label %catch.body unwind label %catch.end + %cs1 = catchswitch within none [label %catch.body] unwind to caller catch.body: - catchret %catch to label %exit - -catch.end: - catchendpad unwind to caller + %catch = catchpad within %cs1 [] + catchret from %catch to label %exit exit: unreachable Index: test/Transforms/Sink/catchswitch.ll =================================================================== --- /dev/null +++ test/Transforms/Sink/catchswitch.ll @@ -0,0 +1,37 @@ +; RUN: opt -sink -S < %s | FileCheck %s + +target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" +target triple = "i686-pc-windows-msvc" + +define void @h() personality i32 (...)* @__CxxFrameHandler3 { +entry: + %call = call i32 @g(i32 1) readnone + invoke void @_CxxThrowException(i8* null, i8* null) noreturn + to label %unreachable unwind label %catch.dispatch + +catch.dispatch: ; preds = %entry + %cs = catchswitch within none [label %catch] unwind to caller + +catch: ; preds = %catch.dispatch + %cp = catchpad within %cs [i8* null, i32 64, i8* null] + catchret from %cp to label %try.cont + +try.cont: ; preds = %catch + call void @k(i32 %call) + ret void + +unreachable: ; preds = %entry + unreachable +} + +declare x86_stdcallcc void @_CxxThrowException(i8*, i8*) + +declare i32 @__CxxFrameHandler3(...) + +declare i32 @g(i32) readnone + +declare void @k(i32) + +; CHECK-LABEL: define void @h( +; CHECK: call i32 @g(i32 1) +; CHECK-NEXT: invoke void @_CxxThrowException( Index: test/Verifier/invalid-eh.ll =================================================================== --- /dev/null +++ test/Verifier/invalid-eh.ll @@ -0,0 +1,38 @@ +; RUN: sed -e s/.T1:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK1 %s +; RUN: sed -e s/.T2:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK2 %s +; RUN: sed -e s/.T3:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK3 %s +; RUN: sed -e s/.T4:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK4 %s + +;T1: define void @f() { +;T1: entry: +;T1: catchret from undef to label %next +;T1: ; CHECK1: CatchReturnInst needs to be provided a CatchPad +;T1: next: +;T1: unreachable +;T1: } + +;T2: define void @f() { +;T2: entry: +;T2: %x = cleanuppad within none [] +;T2: ; catchret's first operand's operator must be catchpad +;T2: catchret from %x to label %entry +;T2: ; CHECK2: CatchReturnInst needs to be provided a CatchPad +;T2: } + +;T3: define void @f() { +;T3: entry: +;T3: cleanupret from undef unwind label %next +;T3: ; CHECK3: CleanupReturnInst needs to be provided a CleanupPad +;T3: next: +;T3: unreachable +;T3: } + +;T4: define void @f() { +;T4: entry: +;T4: %cs = catchswitch within none [label %next] unwind to caller +;T4: next: +;T4: %x = catchpad within %cs [] +;T4: ; cleanupret first operand's operator must be cleanuppad +;T4: cleanupret from %x unwind to caller +;T4: ; CHECK4: CleanupReturnInst needs to be provided a CleanupPad +;T4: } Index: tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp =================================================================== --- tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -259,8 +259,6 @@ STRINGIFY_CODE(FUNC_CODE, INST_CLEANUPRET) STRINGIFY_CODE(FUNC_CODE, INST_CATCHRET) STRINGIFY_CODE(FUNC_CODE, INST_CATCHPAD) - STRINGIFY_CODE(FUNC_CODE, INST_CLEANUPENDPAD) - STRINGIFY_CODE(FUNC_CODE, INST_CATCHENDPAD) STRINGIFY_CODE(FUNC_CODE, INST_TERMINATEPAD) STRINGIFY_CODE(FUNC_CODE, INST_PHI) STRINGIFY_CODE(FUNC_CODE, INST_ALLOCA)