[llvm] 1a949c8 - [Windows SEH]: HARDWARE EXCEPTION HANDLING (MSVC -EHa) - Part 2

via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 1 23:45:10 PST 2022


Author: tentzen
Date: 2022-12-01T23:44:25-08:00
New Revision: 1a949c871ab4a6b6d792849d3e8c0fa6958d27f5

URL: https://github.com/llvm/llvm-project/commit/1a949c871ab4a6b6d792849d3e8c0fa6958d27f5
DIFF: https://github.com/llvm/llvm-project/commit/1a949c871ab4a6b6d792849d3e8c0fa6958d27f5.diff

LOG: [Windows SEH]: HARDWARE EXCEPTION HANDLING (MSVC -EHa) - Part 2

This patch is the Part-2 (BE LLVM) implementation of HW Exception handling.
Part-1 (FE Clang) was committed in 797ad701522988e212495285dade8efac41a24d4.

This new feature adds the support of Hardware Exception for Microsoft Windows
SEH (Structured Exception Handling).

Compiler options:
  For clang-cl.exe, the option is -EHa, the same as MSVC.
  For clang.exe, the extra option is -fasync-exceptions,
  plus -triple x86_64-windows -fexceptions and -fcxx-exceptions as usual.

NOTE:: Without the -EHa or -fasync-exceptions, this patch is a NO-DIFF change.

The rules for C code:
For C-code, one way (MSVC approach) to achieve SEH -EHa semantic is to follow three rules:
  First, no exception can move in or out of _try region., i.e., no "potential faulty
    instruction can be moved across _try boundary.
  Second, the order of exceptions for instructions 'directly' under a _try must be preserved
    (not applied to those in callees).
  Finally, global states (local/global/heap variables) that can be read outside of _try region
    must be updated in memory (not just in register) before the subsequent exception occurs.

The impact to C++ code:
  Although SEH is a feature for C code, -EHa does have a profound effect on C++
  side. When a C++ function (in the same compilation unit with option -EHa ) is
  called by a SEH C function, a hardware exception occurs in C++ code can also
  be handled properly by an upstream SEH _try-handler or a C++ catch(...).
  As such, when that happens in the middle of an object's life scope, the dtor
  must be invoked the same way as C++ Synchronous Exception during unwinding process.

Design:
A natural way to achieve the rules above in LLVM today is to allow an EH edge
added on memory/computation instruction (previous iload/istore idea) so that
exception path is modeled in Flow graph preciously. However, tracking every
single memory instruction and potential faulty instruction can create many
Invokes, complicate flow graph and possibly result in negative performance
impact for downstream optimization and code generation. Making all
optimizations be aware of the new semantic is also substantial.

This design does not intend to model exception path at instruction level.
Instead, the proposed design tracks and reports EH state at BLOCK-level to
reduce the complexity of flow graph and minimize the performance-impact on CPP
code under -EHa option.
One key element of this design is the ability to compute State number at
block-level. Our algorithm is based on the following rationales:

A _try scope is always a SEME (Single Entry Multiple Exits) region as jumping
into a _try is not allowed. The single entry must start with a seh_try_begin()
invoke with a correct State number that is the initial state of the SEME.
Through control-flow, state number is propagated into all blocks. Side exits
marked by seh_try_end() will unwind to parent state based on existing SEHUnwindMap[].
Note side exits can ONLY jump into parent scopes (lower state number).
Thus, when a block succeeds various states from its predecessors, the lowest
State triumphs others.  If some exits flow to unreachable, propagation on those
paths terminate, not affecting remaining blocks.
For CPP code, object lifetime region is usually a SEME as SEH _try.
However there is one rare exception: jumping into a lifetime that has Dtor but
has no Ctor is warned, but allowed:

Warning: jump bypasses variable with a non-trivial destructor

In that case, the region is actually a MEME (multiple entry multiple exits).
Our solution is to inject a eha_scope_begin() invoke in the side entry block to
ensure a correct State.
Implementation:
Part-1: Clang implementation (already in):
Please see commit 797ad701522988e212495285dade8efac41a24d4).

Part-2 : LLVM implementation described below.

For both C++ & C-code, the state of each block is computed at the same place in
BE (WinEHPreparing pass) where all other EH tables/maps are calculated.
In addition to _scope_begin & _scope_end, the computation of block state also
rely on the existing State tracking code (UnwindMap and InvokeStateMap).

For both C++ & C-code, the state of each block with potential trap instruction
is marked and reported in DAG Instruction Selection pass, the same place where
the state for -EHsc (synchronous exceptions) is done.
If the first instruction in a reported block scope can trap, a Nop is injected
before this instruction. This nop is needed to accommodate LLVM Windows EH
implementation, in which the address in IPToState table is offset by +1.
(note the purpose of that is to ensure the return address of a call is in the
same scope as the call address.

The handler for catch(...) for -EHa must handle HW exception. So it is
'adjective' flag is reset (it cannot be IsStdDotDot (0x40) that only catches
C++ exceptions).
Suppress push/popTerminate() scope (from noexcept/noTHrow) so that HW
exceptions can be passed through.

Original llvm-dev [RFC] discussions can be found in these two threads below:
https://lists.llvm.org/pipermail/llvm-dev/2020-March/140541.html
https://lists.llvm.org/pipermail/llvm-dev/2020-April/141338.html

Differential Revision: https://reviews.llvm.org/D102817/new/

Added: 
    llvm/test/CodeGen/X86/windows-seh-EHa-CppCatchDotDotDot.ll
    llvm/test/CodeGen/X86/windows-seh-EHa-CppCondiTemps.ll
    llvm/test/CodeGen/X86/windows-seh-EHa-CppDtors01.ll
    llvm/test/CodeGen/X86/windows-seh-EHa-TryInFinally.ll

Modified: 
    llvm/include/llvm/CodeGen/SelectionDAGISel.h
    llvm/include/llvm/CodeGen/WinEHFuncInfo.h
    llvm/include/llvm/IR/BasicBlock.h
    llvm/lib/Analysis/EHPersonalities.cpp
    llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
    llvm/lib/CodeGen/AsmPrinter/WinException.cpp
    llvm/lib/CodeGen/BranchFolding.cpp
    llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
    llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
    llvm/lib/CodeGen/WinEHPrepare.cpp
    llvm/lib/IR/BasicBlock.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/CodeGen/SelectionDAGISel.h b/llvm/include/llvm/CodeGen/SelectionDAGISel.h
index c395452713ad..99a4dac4d5eb 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAGISel.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAGISel.h
@@ -339,6 +339,9 @@ class SelectionDAGISel : public MachineFunctionPass {
   /// instruction selected, false if no code should be emitted for it.
   bool PrepareEHLandingPad();
 
+  // Mark and Report IPToState for each Block under AsynchEH
+  void reportIPToStateForBlocks(MachineFunction *Fn);
+
   /// Perform instruction selection on all basic blocks in the function.
   void SelectAllBasicBlocks(const Function &Fn);
 

diff  --git a/llvm/include/llvm/CodeGen/WinEHFuncInfo.h b/llvm/include/llvm/CodeGen/WinEHFuncInfo.h
index f098316de793..c007d462e070 100644
--- a/llvm/include/llvm/CodeGen/WinEHFuncInfo.h
+++ b/llvm/include/llvm/CodeGen/WinEHFuncInfo.h
@@ -92,6 +92,7 @@ struct WinEHFuncInfo {
   DenseMap<const FuncletPadInst *, int> FuncletBaseStateMap;
   DenseMap<const InvokeInst *, int> InvokeStateMap;
   DenseMap<MCSymbol *, std::pair<int, MCSymbol *>> LabelToStateMap;
+  DenseMap<const BasicBlock *, int> BlockToStateMap; // for AsynchEH
   SmallVector<CxxUnwindMapEntry, 4> CxxUnwindMap;
   SmallVector<WinEHTryBlockMapEntry, 4> TryBlockMap;
   SmallVector<SEHUnwindMapEntry, 4> SEHUnwindMap;
@@ -104,6 +105,8 @@ struct WinEHFuncInfo {
   void addIPToStateRange(const InvokeInst *II, MCSymbol *InvokeBegin,
                          MCSymbol *InvokeEnd);
 
+  void addIPToStateRange(int State, MCSymbol *InvokeBegin, MCSymbol *InvokeEnd);
+
   int EHRegNodeFrameIndex = std::numeric_limits<int>::max();
   int EHRegNodeEndOffset = std::numeric_limits<int>::max();
   int EHGuardFrameIndex = std::numeric_limits<int>::max();
@@ -123,6 +126,12 @@ void calculateSEHStateNumbers(const Function *ParentFn,
 
 void calculateClrEHStateNumbers(const Function *Fn, WinEHFuncInfo &FuncInfo);
 
+// For AsynchEH (VC++ option -EHa)
+void calculateCXXStateForAsynchEH(const BasicBlock *BB, int State,
+                                  WinEHFuncInfo &FuncInfo);
+void calculateSEHStateForAsynchEH(const BasicBlock *BB, int State,
+                                  WinEHFuncInfo &FuncInfo);
+
 } // end namespace llvm
 
 #endif // LLVM_CODEGEN_WINEHFUNCINFO_H

diff  --git a/llvm/include/llvm/IR/BasicBlock.h b/llvm/include/llvm/IR/BasicBlock.h
index 57a2ace099ad..e942756d87b4 100644
--- a/llvm/include/llvm/IR/BasicBlock.h
+++ b/llvm/include/llvm/IR/BasicBlock.h
@@ -205,6 +205,15 @@ class BasicBlock final : public Value, // Basic blocks are data objects also
         .getNonConst();
   }
 
+  /// Returns the first potential AsynchEH faulty instruction
+  /// currently it checks for loads/stores (which may dereference a null
+  /// pointer) and calls/invokes (which may propagate exceptions)
+  const Instruction* getFirstMayFaultInst() const;
+  Instruction* getFirstMayFaultInst() {
+      return const_cast<Instruction*>(
+          static_cast<const BasicBlock*>(this)->getFirstMayFaultInst());
+  }
+
   /// Return a const iterator range over the instructions in the block, skipping
   /// any debug instructions. Skip any pseudo operations as well if \c
   /// SkipPseudoOp is true.

diff  --git a/llvm/lib/Analysis/EHPersonalities.cpp b/llvm/lib/Analysis/EHPersonalities.cpp
index 277ff6ba735f..3871db59a159 100644
--- a/llvm/lib/Analysis/EHPersonalities.cpp
+++ b/llvm/lib/Analysis/EHPersonalities.cpp
@@ -13,6 +13,7 @@
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/Instructions.h"
+#include "llvm/IR/Module.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
 using namespace llvm;
@@ -79,7 +80,11 @@ bool llvm::canSimplifyInvokeNoUnwind(const Function *F) {
   // We can't simplify any invokes to nounwind functions if the personality
   // function wants to catch asynch exceptions.  The nounwind attribute only
   // implies that the function does not throw synchronous exceptions.
-  return !isAsynchronousEHPersonality(Personality);
+
+  // Cannot simplify CXX Personality under AsynchEH
+  const llvm::Module *M = (const llvm::Module *)F->getParent();
+  bool EHa = M->getModuleFlag("eh-asynch");
+  return !EHa && !isAsynchronousEHPersonality(Personality);
 }
 
 DenseMap<BasicBlock *, ColorVector> llvm::colorEHFunclets(Function &F) {

diff  --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 1d148cd7b11b..c3e057359ae9 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1584,6 +1584,7 @@ void AsmPrinter::emitFunctionBody() {
   // Print out code for the function.
   bool HasAnyRealCode = false;
   int NumInstsInFunction = 0;
+  bool IsEHa = MMI->getModule()->getModuleFlag("eh-asynch");
 
   bool CanDoExtraAnalysis = ORE->allowExtraAnalysis(DEBUG_TYPE);
   for (auto &MBB : *MF) {
@@ -1622,10 +1623,25 @@ void AsmPrinter::emitFunctionBody() {
         emitFrameAlloc(MI);
         break;
       case TargetOpcode::ANNOTATION_LABEL:
-      case TargetOpcode::EH_LABEL:
       case TargetOpcode::GC_LABEL:
         OutStreamer->emitLabel(MI.getOperand(0).getMCSymbol());
         break;
+      case TargetOpcode::EH_LABEL:
+        OutStreamer->emitLabel(MI.getOperand(0).getMCSymbol());
+        // For AsynchEH, insert a Nop if followed by a trap inst
+        //   Or the exception won't be caught.
+        //   (see MCConstantExpr::create(1,..) in WinException.cpp)
+        //  Ignore SDiv/UDiv because a DIV with Const-0 divisor
+        //    must have being turned into an UndefValue.
+        //  Div with variable opnds won't be the first instruction in
+        //  an EH region as it must be led by at least a Load
+        {
+          auto MI2 = std::next(MI.getIterator());
+          if (IsEHa && MI2 != MBB.end() &&
+              (MI2->mayLoadOrStore() || MI2->mayRaiseFPException()))
+            emitNops(1);
+        }
+        break;
       case TargetOpcode::INLINEASM:
       case TargetOpcode::INLINEASM_BR:
         emitInlineAsm(&MI);

diff  --git a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp
index 2f1f15e1de39..4dc0983ae69e 100644
--- a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp
@@ -770,7 +770,11 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
   OS.emitInt32(0);
 
   AddComment("EHFlags");
-  OS.emitInt32(1);
+  if (MMI->getModule()->getModuleFlag("eh-asynch")) {
+    OS.emitInt32(0);
+  } else {
+    OS.emitInt32(1);
+  }
 
   // UnwindMapEntry {
   //   int32_t ToState;

diff  --git a/llvm/lib/CodeGen/BranchFolding.cpp b/llvm/lib/CodeGen/BranchFolding.cpp
index 07be03d2dab9..2b604aa82ee8 100644
--- a/llvm/lib/CodeGen/BranchFolding.cpp
+++ b/llvm/lib/CodeGen/BranchFolding.cpp
@@ -1207,7 +1207,7 @@ bool BranchFolder::OptimizeBranches(MachineFunction &MF) {
     MadeChange |= OptimizeBlock(&MBB);
 
     // If it is dead, remove it.
-    if (MBB.pred_empty()) {
+    if (MBB.pred_empty() && !MBB.isMachineBlockAddressTaken()) {
       RemoveDeadBlock(&MBB);
       MadeChange = true;
       ++NumDeadBlocks;

diff  --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index a5071abc6e49..8f857938e6ca 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -2926,6 +2926,7 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) {
   // catchswitch for successors.
   MachineBasicBlock *Return = FuncInfo.MBBMap[I.getSuccessor(0)];
   const BasicBlock *EHPadBB = I.getSuccessor(1);
+  MachineBasicBlock *EHPadMBB = FuncInfo.MBBMap[EHPadBB];
 
   // Deopt bundles are lowered in LowerCallSiteWithDeoptBundle, and we don't
   // have to do anything here to lower funclet bundles.
@@ -2950,6 +2951,10 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) {
     case Intrinsic::seh_scope_begin:
     case Intrinsic::seh_try_end:
     case Intrinsic::seh_scope_end:
+      if (EHPadMBB)
+          // a block referenced by EH table
+          // so dtor-funclet not removed by opts
+          EHPadMBB->setMachineBlockAddressTaken();
       break;
     case Intrinsic::experimental_patchpoint_void:
     case Intrinsic::experimental_patchpoint_i64:

diff  --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index 30fab77f8621..338ccc8748f6 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -59,6 +59,7 @@
 #include "llvm/CodeGen/TargetRegisterInfo.h"
 #include "llvm/CodeGen/TargetSubtargetInfo.h"
 #include "llvm/CodeGen/ValueTypes.h"
+#include "llvm/CodeGen/WinEHFuncInfo.h"
 #include "llvm/IR/BasicBlock.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DataLayout.h"
@@ -1280,6 +1281,43 @@ bool SelectionDAGISel::PrepareEHLandingPad() {
   return true;
 }
 
+// Mark and Report IPToState for each Block under IsEHa
+void SelectionDAGISel::reportIPToStateForBlocks(MachineFunction *MF) {
+  MachineModuleInfo &MMI = MF->getMMI();
+  llvm::WinEHFuncInfo *EHInfo = MF->getWinEHFuncInfo();
+  if (!EHInfo)
+    return;
+  for (auto MBBI = MF->begin(), E = MF->end(); MBBI != E; ++MBBI) {
+    MachineBasicBlock *MBB = &*MBBI;
+    const BasicBlock *BB = MBB->getBasicBlock();
+    int State = EHInfo->BlockToStateMap[BB];
+    if (BB->getFirstMayFaultInst()) {
+      // Report IP range only for blocks with Faulty inst
+      auto MBBb = MBB->getFirstNonPHI();
+      MachineInstr *MIb = &*MBBb;
+      if (MIb->isTerminator())
+        continue;
+
+      // Insert EH Labels
+      MCSymbol *BeginLabel = MMI.getContext().createTempSymbol();
+      MCSymbol *EndLabel = MMI.getContext().createTempSymbol();
+      EHInfo->addIPToStateRange(State, BeginLabel, EndLabel);
+      BuildMI(*MBB, MBBb, SDB->getCurDebugLoc(),
+              TII->get(TargetOpcode::EH_LABEL))
+          .addSym(BeginLabel);
+      auto MBBe = MBB->instr_end();
+      MachineInstr *MIe = &*(--MBBe);
+      // insert before (possible multiple) terminators
+      while (MIe->isTerminator())
+        MIe = &*(--MBBe);
+      ++MBBe;
+      BuildMI(*MBB, MBBe, SDB->getCurDebugLoc(),
+              TII->get(TargetOpcode::EH_LABEL))
+          .addSym(EndLabel);
+    }
+  }
+}
+
 /// isFoldedOrDeadInstruction - Return true if the specified instruction is
 /// side-effect free and is either dead or folded into a generated instruction.
 /// Return false if it needs to be emitted.
@@ -1612,6 +1650,10 @@ void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) {
     ElidedArgCopyInstrs.clear();
   }
 
+  // AsynchEH: Report Block State under -AsynchEH
+  if (Fn.getParent()->getModuleFlag("eh-asynch"))
+    reportIPToStateForBlocks(MF);
+
   SP.copyToMachineFrameInfo(MF->getFrameInfo());
 
   SwiftError->propagateVRegs();

diff  --git a/llvm/lib/CodeGen/WinEHPrepare.cpp b/llvm/lib/CodeGen/WinEHPrepare.cpp
index 8f5d9e9b296c..47b3e8ebe32a 100644
--- a/llvm/lib/CodeGen/WinEHPrepare.cpp
+++ b/llvm/lib/CodeGen/WinEHPrepare.cpp
@@ -216,6 +216,127 @@ static void calculateStateNumbersForInvokes(const Function *Fn,
   }
 }
 
+// See comments below for calculateSEHStateForAsynchEH().
+// State - incoming State of normal paths
+struct WorkItem {
+  const BasicBlock *Block;
+  int State;
+  WorkItem(const BasicBlock *BB, int St) {
+    Block = BB;
+    State = St;
+  }
+};
+void llvm::calculateCXXStateForAsynchEH(const BasicBlock *BB, int State,
+                                        WinEHFuncInfo &EHInfo) {
+  SmallVector<struct WorkItem *, 8> WorkList;
+  struct WorkItem *WI = new WorkItem(BB, State);
+  WorkList.push_back(WI);
+
+  while (!WorkList.empty()) {
+    WI = WorkList.pop_back_val();
+    const BasicBlock *BB = WI->Block;
+    int State = WI->State;
+    delete WI;
+    if (EHInfo.BlockToStateMap.count(BB) && EHInfo.BlockToStateMap[BB] <= State)
+      continue; // skip blocks already visited by lower State
+
+    const llvm::Instruction *I = BB->getFirstNonPHI();
+    const llvm::Instruction *TI = BB->getTerminator();
+    if (I->isEHPad())
+      State = EHInfo.EHPadStateMap[I];
+    EHInfo.BlockToStateMap[BB] = State; // Record state, also flag visiting
+
+    if ((isa<CleanupReturnInst>(TI) || isa<CatchReturnInst>(TI)) && State > 0) {
+      // Retrive the new State
+      State = EHInfo.CxxUnwindMap[State].ToState; // Retrive next State
+    } else if (isa<InvokeInst>(TI)) {
+      auto *Call = dyn_cast<CallBase>(TI);
+      const Function *Fn = Call->getCalledFunction();
+      if (Fn && Fn->isIntrinsic() &&
+          (Fn->getIntrinsicID() == Intrinsic::seh_scope_begin ||
+           Fn->getIntrinsicID() == Intrinsic::seh_try_begin))
+        // Retrive the new State from seh_scope_begin
+        State = EHInfo.InvokeStateMap[cast<InvokeInst>(TI)];
+      else if (Fn && Fn->isIntrinsic() &&
+               (Fn->getIntrinsicID() == Intrinsic::seh_scope_end ||
+                Fn->getIntrinsicID() == Intrinsic::seh_try_end)) {
+        // In case of conditional ctor, let's retrieve State from Invoke
+        State = EHInfo.InvokeStateMap[cast<InvokeInst>(TI)];
+        // end of current state, retrive new state from UnwindMap
+        State = EHInfo.CxxUnwindMap[State].ToState;
+      }
+    }
+    // Continue push successors into worklist
+    for (auto *SuccBB : successors(BB)) {
+      WI = new WorkItem(SuccBB, State);
+      WorkList.push_back(WI);
+    }
+  }
+}
+
+// The central theory of this routine is based on the following:
+//   A _try scope is always a SEME (Single Entry Multiple Exits) region
+//     as jumping into a _try is not allowed
+//   The single entry must start with a seh_try_begin() invoke with a
+//     correct State number that is the initial state of the SEME.
+//   Through control-flow, state number is propagated into all blocks.
+//   Side exits marked by seh_try_end() will unwind to parent state via
+//     existing SEHUnwindMap[].
+//   Side exits can ONLY jump into parent scopes (lower state number).
+//   Thus, when a block succeeds various states from its predecessors,
+//     the lowest State trumphs others.
+//   If some exits flow to unreachable, propagation on those paths terminate,
+//     not affecting remaining blocks.
+void llvm::calculateSEHStateForAsynchEH(const BasicBlock *BB, int State,
+                                        WinEHFuncInfo &EHInfo) {
+  SmallVector<struct WorkItem *, 8> WorkList;
+  struct WorkItem *WI = new WorkItem(BB, State);
+  WorkList.push_back(WI);
+
+  while (!WorkList.empty()) {
+    WI = WorkList.pop_back_val();
+    const BasicBlock *BB = WI->Block;
+    int State = WI->State;
+    delete WI;
+    if (EHInfo.BlockToStateMap.count(BB) && EHInfo.BlockToStateMap[BB] <= State)
+      continue; // skip blocks already visited by lower State
+
+    const llvm::Instruction *I = BB->getFirstNonPHI();
+    const llvm::Instruction *TI = BB->getTerminator();
+    if (I->isEHPad())
+      State = EHInfo.EHPadStateMap[I];
+    EHInfo.BlockToStateMap[BB] = State; // Record state
+
+    if (isa<CatchPadInst>(I) && isa<CatchReturnInst>(TI)) {
+      const Constant *FilterOrNull = cast<Constant>(
+          cast<CatchPadInst>(I)->getArgOperand(0)->stripPointerCasts());
+      const Function *Filter = dyn_cast<Function>(FilterOrNull);
+      if (!Filter || !Filter->getName().startswith("__IsLocalUnwind"))
+        State = EHInfo.SEHUnwindMap[State].ToState; // Retrive next State
+    } else if ((isa<CleanupReturnInst>(TI) || isa<CatchReturnInst>(TI)) &&
+               State > 0) {
+      // Retrive the new State.
+      State = EHInfo.SEHUnwindMap[State].ToState; // Retrive next State
+    } else if (isa<InvokeInst>(TI)) {
+      auto *Call = dyn_cast<CallBase>(TI);
+      const Function *Fn = Call->getCalledFunction();
+      if (Fn && Fn->isIntrinsic() &&
+          Fn->getIntrinsicID() == Intrinsic::seh_try_begin)
+        // Retrive the new State from seh_try_begin
+        State = EHInfo.InvokeStateMap[cast<InvokeInst>(TI)];
+      else if (Fn && Fn->isIntrinsic() &&
+               Fn->getIntrinsicID() == Intrinsic::seh_try_end)
+        // end of current state, retrive new state from UnwindMap
+        State = EHInfo.SEHUnwindMap[State].ToState;
+    }
+    // Continue push successors into worklist
+    for (auto *SuccBB : successors(BB)) {
+      WI = new WorkItem(SuccBB, State);
+      WorkList.push_back(WI);
+    }
+  }
+}
+
 // 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,
@@ -276,6 +397,7 @@ static void calculateCXXStateNumbers(WinEHFuncInfo &FuncInfo,
 
     for (const auto *CatchPad : Handlers) {
       FuncInfo.FuncletBaseStateMap[CatchPad] = CatchLow;
+      FuncInfo.EHPadStateMap[CatchPad] = CatchLow;
       for (const User *U : CatchPad->users()) {
         const auto *UserI = cast<Instruction>(U);
         if (auto *InnerCatchSwitch = dyn_cast<CatchSwitchInst>(UserI)) {
@@ -384,6 +506,7 @@ static void calculateSEHStateNumbers(WinEHFuncInfo &FuncInfo,
 
     // Everything in the __try block uses TryState as its parent state.
     FuncInfo.EHPadStateMap[CatchSwitch] = TryState;
+    FuncInfo.EHPadStateMap[CatchPad] = TryState;
     LLVM_DEBUG(dbgs() << "Assigning state #" << TryState << " to BB "
                       << CatchPadBB->getName() << '\n');
     for (const BasicBlock *PredBlock : predecessors(BB))
@@ -464,6 +587,12 @@ void llvm::calculateSEHStateNumbers(const Function *Fn,
   }
 
   calculateStateNumbersForInvokes(Fn, FuncInfo);
+
+  bool IsEHa = Fn->getParent()->getModuleFlag("eh-asynch");
+  if (IsEHa) {
+    const BasicBlock *EntryBB = &(Fn->getEntryBlock());
+    calculateSEHStateForAsynchEH(EntryBB, -1, FuncInfo);
+  }
 }
 
 void llvm::calculateWinCXXEHStateNumbers(const Function *Fn,
@@ -482,6 +611,12 @@ void llvm::calculateWinCXXEHStateNumbers(const Function *Fn,
   }
 
   calculateStateNumbersForInvokes(Fn, FuncInfo);
+
+  bool IsEHa = Fn->getParent()->getModuleFlag("eh-asynch");
+  if (IsEHa) {
+    const BasicBlock *EntryBB = &(Fn->getEntryBlock());
+    calculateCXXStateForAsynchEH(EntryBB, -1, FuncInfo);
+  }
 }
 
 static int addClrEHHandler(WinEHFuncInfo &FuncInfo, int HandlerParentState,
@@ -1253,4 +1388,9 @@ void WinEHFuncInfo::addIPToStateRange(const InvokeInst *II,
   LabelToStateMap[InvokeBegin] = std::make_pair(InvokeStateMap[II], InvokeEnd);
 }
 
+void WinEHFuncInfo::addIPToStateRange(int State, MCSymbol* InvokeBegin,
+    MCSymbol* InvokeEnd) {
+    LabelToStateMap[InvokeBegin] = std::make_pair(State, InvokeEnd);
+}
+
 WinEHFuncInfo::WinEHFuncInfo() = default;

diff  --git a/llvm/lib/IR/BasicBlock.cpp b/llvm/lib/IR/BasicBlock.cpp
index 16addda83e42..e461628b07ee 100644
--- a/llvm/lib/IR/BasicBlock.cpp
+++ b/llvm/lib/IR/BasicBlock.cpp
@@ -206,6 +206,15 @@ const CallInst *BasicBlock::getPostdominatingDeoptimizeCall() const {
   return BB->getTerminatingDeoptimizeCall();
 }
 
+const Instruction *BasicBlock::getFirstMayFaultInst() const {
+  if (InstList.empty())
+    return nullptr;
+  for (const Instruction &I : *this)
+    if (isa<LoadInst>(I) || isa<StoreInst>(I) || isa<CallBase>(I))
+      return &I;
+  return nullptr;
+}
+
 const Instruction* BasicBlock::getFirstNonPHI() const {
   for (const Instruction &I : *this)
     if (!isa<PHINode>(I))

diff  --git a/llvm/test/CodeGen/X86/windows-seh-EHa-CppCatchDotDotDot.ll b/llvm/test/CodeGen/X86/windows-seh-EHa-CppCatchDotDotDot.ll
new file mode 100644
index 000000000000..2b09c0133c1d
--- /dev/null
+++ b/llvm/test/CodeGen/X86/windows-seh-EHa-CppCatchDotDotDot.ll
@@ -0,0 +1,290 @@
+; RUN: llc -verify-machineinstrs < %s | FileCheck %s
+
+; CHECK-LABEL: "$cppxdata$?crash@@YAXH at Z":
+; CHECK:	.long	("$stateUnwindMap$?crash@@YAXH at Z")
+; CHECK:        .long   ("$tryMap$?crash@@YAXH at Z")@IMGREL # TryBlockMap
+; CHECK-NEXT:   .long   6                       # IPMapEntries
+; CHECK-NEXT:	.long	("$ip2state$?crash@@YAXH at Z")
+
+; CHECK-LABEL: "$stateUnwindMap$?crash@@YAXH at Z":
+; CHECK-NEXT:        .long   -1                
+; CHECK-NEXT:        .long   0                 
+; CHECK-NEXT:        .long   0                 
+; CHECK-NEXT:        .long   "?dtor$
+; CHECK-NEXT:        .long   -1                
+; CHECK-NEXT:        .long   0                 
+
+; CHECK-LABEL: "$tryMap$?crash@@YAXH at Z":
+; CHECK-NEXT:        .long   0             
+; CHECK-NEXT:        .long   1             
+; CHECK-NEXT:        .long   2             
+; CHECK-NEXT:        .long   1             
+; CHECK-NEXT:        .long   ("$handlerMap$
+
+; CHECK:       "$handlerMap$0$?crash@@YAXH at Z"
+; CHECK-NEXT:        .long   0             
+; CHECK-NEXT:        .long   0             
+; CHECK-NEXT:        .long   0             
+; CHECK-NEXT:        .long   "?catch$ 
+
+; CHECK-LABEL: "$ip2state$?crash@@YAXH at Z":
+; CHECK-NEXT:	.long	.Lfunc_begin0 at IMGREL
+; CHECK-NEXT:	.long	-1                  
+; CHECK-NEXT:	.long	.Ltmp     
+; CHECK-NEXT:	.long	0                   
+; CHECK-NEXT:	.long	.Ltmp     
+; CHECK-NEXT:	.long	1                   
+; CHECK-NEXT:	.long	.Ltmp
+; CHECK-NEXT:	.long	0                  
+; CHECK-NEXT:	.long	.Ltmp
+; CHECK-NEXT:	.long	-1                                  
+; CHECK-NEXT:	.long	"?catch$
+; CHECK-NEXT:	.long	2                  
+
+; ModuleID = 'windows-seh-EHa-CppCatchDotDotDot.cpp'
+source_filename = "windows-seh-EHa-CppCatchDotDotDot.cpp"
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-windows-msvc"
+
+%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
+%eh.CatchableType = type { i32, i32, i32, i32, i32, i32, i32 }
+%eh.CatchableTypeArray.1 = type { i32, [1 x i32] }
+%eh.ThrowInfo = type { i32, i32, i32, i32 }
+%struct.A = type { i8 }
+
+$"??_C at _0BJ@EIKFKKLB@?5in?5catch?$CI?4?4?4?$CJ?5funclet?5?6?$AA@" = comdat any
+
+$"??_R0H at 8" = comdat any
+
+$"_CT??_R0H at 84" = comdat any
+
+$_CTA1H = comdat any
+
+$_TI1H = comdat any
+
+$"??_C at _0CN@MKCAOFNA@?5Test?5CPP?5unwind?3?5in?5except?5hand@" = comdat any
+
+$"??_C at _0N@LJHFFAKD@?5in?5A?5ctor?5?6?$AA@" = comdat any
+
+$"??_C at _0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@" = comdat any
+
+@"?pt1@@3PEAHEA" = dso_local global i32* null, align 8
+@"?pt2@@3PEAHEA" = dso_local global i32* null, align 8
+@"?pt3@@3PEAHEA" = dso_local global i32* null, align 8
+@"?g@@3HA" = dso_local global i32 0, align 4
+@"??_C at _0BJ@EIKFKKLB@?5in?5catch?$CI?4?4?4?$CJ?5funclet?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [25 x i8] c" in catch(...) funclet \0A\00", comdat, align 1
+@"??_7type_info@@6B@" = external constant i8*
+@"??_R0H at 8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
+ at __ImageBase = external dso_local constant i8
+@"_CT??_R0H at 84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"??_R0H at 8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 4, i32 0 }, section ".xdata", comdat
+ at _CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0H at 84" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat
+ at _TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableTypeArray.1* @_CTA1H to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section ".xdata", comdat
+@"??_C at _0CN@MKCAOFNA@?5Test?5CPP?5unwind?3?5in?5except?5hand@" = linkonce_odr dso_local unnamed_addr constant [45 x i8] c" Test CPP unwind: in except handler i = %d \0A\00", comdat, align 1
+@"??_C at _0N@LJHFFAKD@?5in?5A?5ctor?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [13 x i8] c" in A ctor \0A\00", comdat, align 1
+@"??_C at _0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [13 x i8] c" in A dtor \0A\00", comdat, align 1
+
+; Function Attrs: noinline nounwind optnone
+define dso_local void @"?foo@@YAXXZ"() #0 {
+entry:
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4
+  ret void
+}
+
+; Function Attrs: noinline optnone
+define dso_local void @"?crash@@YAXH at Z"(i32 %i) #1 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+  %i.addr = alloca i32, align 4
+  %ObjA = alloca %struct.A, align 1
+  %tmp = alloca i32, align 4
+  store i32 %i, i32* %i.addr, align 4
+  %0 = load i32, i32* %i.addr, align 4
+  store i32 %0, i32* @"?g@@3HA", align 4
+  invoke void @llvm.seh.try.begin()
+          to label %invoke.cont unwind label %catch.dispatch
+
+invoke.cont:                                      ; preds = %entry
+  %call = invoke %struct.A* @"??0A@?1??crash@@YAXH at Z@QEAA at XZ"(%struct.A* %ObjA)
+          to label %invoke.cont1 unwind label %catch.dispatch
+
+invoke.cont1:                                     ; preds = %invoke.cont
+  invoke void @llvm.seh.scope.begin()
+          to label %invoke.cont2 unwind label %ehcleanup
+
+invoke.cont2:                                     ; preds = %invoke.cont1
+  %1 = load i32, i32* %i.addr, align 4
+  %cmp = icmp eq i32 %1, 1
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %invoke.cont2
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %invoke.cont2
+  invoke void @llvm.seh.scope.end()
+          to label %invoke.cont3 unwind label %ehcleanup
+
+invoke.cont3:                                     ; preds = %if.end
+  call void @"??1A@?1??crash@@YAXH at Z@QEAA at XZ"(%struct.A* %ObjA) #6
+  br label %try.cont
+
+ehcleanup:                                        ; preds = %if.end, %invoke.cont1
+  %2 = cleanuppad within none []
+  call void @"??1A@?1??crash@@YAXH at Z@QEAA at XZ"(%struct.A* %ObjA) #6 [ "funclet"(token %2) ]
+  cleanupret from %2 unwind label %catch.dispatch
+
+catch.dispatch:                                   ; preds = %ehcleanup, %invoke.cont, %entry
+  %3 = catchswitch within none [label %catch] unwind to caller
+
+catch:                                            ; preds = %catch.dispatch
+  %4 = catchpad within %3 [i8* null, i32 0, i8* null]
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @"??_C at _0BJ@EIKFKKLB@?5in?5catch?$CI?4?4?4?$CJ?5funclet?5?6?$AA@", i64 0, i64 0)) [ "funclet"(token %4) ]
+  %5 = load i32, i32* %i.addr, align 4
+  %cmp4 = icmp eq i32 %5, 1
+  br i1 %cmp4, label %if.then5, label %if.end6
+
+if.then5:                                         ; preds = %catch
+  %6 = load i32, i32* %i.addr, align 4
+  store i32 %6, i32* %tmp, align 4
+  %7 = bitcast i32* %tmp to i8*
+  call void @_CxxThrowException(i8* %7, %eh.ThrowInfo* @_TI1H) #7 [ "funclet"(token %4) ]
+  unreachable
+
+if.end6:                                          ; preds = %catch
+  catchret from %4 to label %catchret.dest
+
+catchret.dest:                                    ; preds = %if.end6
+  br label %try.cont
+
+try.cont:                                         ; preds = %catchret.dest, %invoke.cont3
+  ret void
+}
+
+; Function Attrs: nounwind willreturn
+declare dso_local void @llvm.seh.try.begin() #2
+
+declare dso_local i32 @__CxxFrameHandler3(...)
+
+; Function Attrs: noinline optnone
+define internal %struct.A* @"??0A@?1??crash@@YAXH at Z@QEAA at XZ"(%struct.A* returned %this) unnamed_addr #1 align 2 {
+entry:
+  %retval = alloca %struct.A*, align 8
+  %this.addr = alloca %struct.A*, align 8
+  store %struct.A* %this, %struct.A** %this.addr, align 8
+  %this1 = load %struct.A*, %struct.A** %this.addr, align 8
+  store %struct.A* %this1, %struct.A** %retval, align 8
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C at _0N@LJHFFAKD@?5in?5A?5ctor?5?6?$AA@", i64 0, i64 0))
+  %0 = load i32, i32* @"?g@@3HA", align 4
+  %cmp = icmp eq i32 %0, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %entry
+  %1 = load %struct.A*, %struct.A** %retval, align 8
+  ret %struct.A* %1
+}
+
+; Function Attrs: nounwind readnone
+declare dso_local void @llvm.seh.scope.begin() #3
+
+; Function Attrs: nounwind readnone
+declare dso_local void @llvm.seh.scope.end() #3
+
+; Function Attrs: noinline nounwind optnone
+define internal void @"??1A@?1??crash@@YAXH at Z@QEAA at XZ"(%struct.A* %this) unnamed_addr #0 align 2 {
+entry:
+  %this.addr = alloca %struct.A*, align 8
+  store %struct.A* %this, %struct.A** %this.addr, align 8
+  %this1 = load %struct.A*, %struct.A** %this.addr, align 8
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C at _0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@", i64 0, i64 0))
+  ret void
+}
+
+declare dso_local void @"?printf@@YAXZZ"(...) #4
+
+declare dso_local void @_CxxThrowException(i8*, %eh.ThrowInfo*)
+
+; Function Attrs: noinline norecurse optnone
+define dso_local i32 @main() #5 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) {
+entry:
+  %retval = alloca i32, align 4
+  %i = alloca i32, align 4
+  %__exception_code = alloca i32, align 4
+  store i32 0, i32* %retval, align 4
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %cmp = icmp slt i32 %0, 2
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  invoke void @llvm.seh.try.begin()
+          to label %invoke.cont unwind label %catch.dispatch
+
+invoke.cont:                                      ; preds = %for.body
+  %1 = load volatile i32, i32* %i, align 4
+  invoke void @"?crash@@YAXH at Z"(i32 %1) #8
+          to label %invoke.cont1 unwind label %catch.dispatch
+
+invoke.cont1:                                     ; preds = %invoke.cont
+  invoke void @llvm.seh.try.end()
+          to label %invoke.cont2 unwind label %catch.dispatch
+
+catch.dispatch:                                   ; preds = %invoke.cont1, %invoke.cont, %for.body
+  %2 = catchswitch within none [label %__except] unwind to caller
+
+__except:                                         ; preds = %catch.dispatch
+  %3 = catchpad within %2 [i8* null]
+  catchret from %3 to label %__except3
+
+__except3:                                        ; preds = %__except
+  %4 = call i32 @llvm.eh.exceptioncode(token %3)
+  store i32 %4, i32* %__exception_code, align 4
+  %5 = load i32, i32* %i, align 4
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([45 x i8], [45 x i8]* @"??_C at _0CN@MKCAOFNA@?5Test?5CPP?5unwind?3?5in?5except?5hand@", i64 0, i64 0), i32 %5)
+  br label %__try.cont
+
+__try.cont:                                       ; preds = %__except3, %invoke.cont2
+  br label %for.inc
+
+for.inc:                                          ; preds = %__try.cont
+  %6 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %6, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+invoke.cont2:                                     ; preds = %invoke.cont1
+  br label %__try.cont
+
+for.end:                                          ; preds = %for.cond
+  ret i32 0
+}
+
+declare dso_local i32 @__C_specific_handler(...)
+
+; Function Attrs: nounwind willreturn
+declare dso_local void @llvm.seh.try.end() #2
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.eh.exceptioncode(token) #3
+
+attributes #0 = { noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { noinline optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind willreturn }
+attributes #3 = { nounwind readnone }
+attributes #4 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #5 = { noinline norecurse optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #6 = { nounwind }
+attributes #7 = { noreturn }
+attributes #8 = { noinline }
+
+!llvm.module.flags = !{!0, !1}
+
+!0 = !{i32 1, !"wchar_size", i32 2}
+!1 = !{i32 2, !"eh-asynch", i32 1}
+
+

diff  --git a/llvm/test/CodeGen/X86/windows-seh-EHa-CppCondiTemps.ll b/llvm/test/CodeGen/X86/windows-seh-EHa-CppCondiTemps.ll
new file mode 100644
index 000000000000..89528d096c43
--- /dev/null
+++ b/llvm/test/CodeGen/X86/windows-seh-EHa-CppCondiTemps.ll
@@ -0,0 +1,543 @@
+; RUN: llc -verify-machineinstrs < %s | FileCheck %s
+
+; CHECK-LABEL: $ip2state$main:
+; CHECK-NEXT:	.long	.Lfunc_begin4 at IMGREL
+; CHECK-NEXT:	.long	-1                              # ToState
+; CHECK-NEXT:	.long	.Ltmp
+; CHECK-NEXT:	.long	0                               # ToState
+; CHECK-NEXT:	.long	.Ltmp
+; CHECK-NEXT:	.long	4                               # ToState
+; CHECK-NEXT:   .long	.Ltmp
+; CHECK:     	.long	5                               # ToState
+; CHECK-NEXT:	.long	.Ltmp
+; CHECK-NEXT:	.long	4                               # ToState
+; CHECK-NEXT:	.long	.Ltmp
+; CHECK-NEXT:	.long	0                               # ToState
+; CHECK-NEXT:	.long	.Ltmp
+; CHECK-NEXT:	.long	2                               # ToState
+; CHECK-NEXT:	.long	.Ltmp
+; CHECK-NEXT:	.long	3                               # ToState
+; CHECK-NEXT:	.long	.Ltmp
+; CHECK-NEXT:	.long	0                               # ToState
+; CHECK-NEXT:	.long	.Ltmp
+; CHECK-NEXT:	.long	1                               # ToState
+; CHECK-NEXT:	.long	.Ltmp
+; CHECK-NEXT:	.long	0                               # ToState
+; CHECK-NEXT:	.long	.Ltmp
+; CHECK-NEXT:	.long	-1                              # ToState
+
+; ModuleID = 'windows-seh-EHa-CppCondiTemps.cpp'
+source_filename = "windows-seh-EHa-CppCondiTemps.cpp"
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-windows-msvc"
+
+%class.B1 = type { i32 }
+%class.B2 = type { %class.B1 }
+%class.B3 = type { %class.B2 }
+
+$"??1B1@@QEAA at XZ" = comdat any
+
+$"??1B2@@QEAA at XZ" = comdat any
+
+$"??0B2@@QEAA at XZ" = comdat any
+
+$"??0B3@@QEAA at XZ" = comdat any
+
+$"??1B3@@QEAA at XZ" = comdat any
+
+$"??0B1@@QEAA at XZ" = comdat any
+
+$"??_C at _0N@FMGAAAAM at in?5B1?5Dtor?5?6?$AA@" = comdat any
+
+$"??_C at _0N@GFONDMMJ at in?5B2?5Dtor?5?6?$AA@" = comdat any
+
+$"??_C at _0N@HCJGCIIK at in?5B3?5Dtor?5?6?$AA@" = comdat any
+
+@"?xxxx@@3HA" = dso_local global i32 0, align 4
+@"?ptr@@3PEAHEA" = dso_local global i32* null, align 8
+@"??_C at _0N@FMGAAAAM at in?5B1?5Dtor?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [13 x i8] c"in B1 Dtor \0A\00", comdat, align 1
+@"??_C at _0N@GFONDMMJ at in?5B2?5Dtor?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [13 x i8] c"in B2 Dtor \0A\00", comdat, align 1
+@"??_C at _0N@HCJGCIIK at in?5B3?5Dtor?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [13 x i8] c"in B3 Dtor \0A\00", comdat, align 1
+
+; Function Attrs: noinline nounwind optnone mustprogress
+define dso_local i32 @"?foo@@YAHH at Z"(i32 %a) #0 {
+entry:
+  %a.addr = alloca i32, align 4
+  store i32 %a, i32* %a.addr, align 4
+  %0 = load i32, i32* @"?xxxx@@3HA", align 4
+  %1 = load i32, i32* %a.addr, align 4
+  %add = add nsw i32 %0, %1
+  ret i32 %add
+}
+
+; Function Attrs: noinline optnone mustprogress
+define dso_local i32 @"?bar@@YAHHVB1@@VB2@@@Z"(i32 %j, i32 %b1Bar.coerce, i32 %b2Bar.coerce) #1 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+  %b1Bar = alloca %class.B1, align 4
+  %b2Bar = alloca %class.B2, align 4
+  %j.addr = alloca i32, align 4
+  %ww = alloca i32, align 4
+  %coerce.dive = getelementptr inbounds %class.B1, %class.B1* %b1Bar, i32 0, i32 0
+  store i32 %b1Bar.coerce, i32* %coerce.dive, align 4
+  %coerce.dive1 = getelementptr inbounds %class.B2, %class.B2* %b2Bar, i32 0, i32 0
+  %coerce.dive2 = getelementptr inbounds %class.B1, %class.B1* %coerce.dive1, i32 0, i32 0
+  store i32 %b2Bar.coerce, i32* %coerce.dive2, align 4
+  invoke void @llvm.seh.scope.begin()
+          to label %invoke.cont unwind label %ehcleanup7
+
+invoke.cont:                                      ; preds = %entry
+  invoke void @llvm.seh.scope.begin()
+          to label %invoke.cont3 unwind label %ehcleanup
+
+invoke.cont3:                                     ; preds = %invoke.cont
+  store i32 %j, i32* %j.addr, align 4
+  %0 = load i32, i32* %j.addr, align 4
+  %cmp = icmp sgt i32 %0, 0
+  br i1 %cmp, label %if.then, label %if.else
+
+if.then:                                          ; preds = %invoke.cont3
+  %data = getelementptr inbounds %class.B1, %class.B1* %b1Bar, i32 0, i32 0
+  %1 = load i32, i32* %data, align 4
+  store i32 %1, i32* %ww, align 4
+  br label %if.end
+
+if.else:                                          ; preds = %invoke.cont3
+  %2 = bitcast %class.B2* %b2Bar to %class.B1*
+  %data4 = getelementptr inbounds %class.B1, %class.B1* %2, i32 0, i32 0
+  %3 = load i32, i32* %data4, align 4
+  store i32 %3, i32* %ww, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then
+  %4 = load i32, i32* %ww, align 4
+  %5 = load i32*, i32** @"?ptr@@3PEAHEA", align 8
+  %6 = load i32, i32* %5, align 4
+  %add = add nsw i32 %4, %6
+  invoke void @llvm.seh.scope.end()
+          to label %invoke.cont5 unwind label %ehcleanup
+
+invoke.cont5:                                     ; preds = %if.end
+  call void @"??1B1@@QEAA at XZ"(%class.B1* nonnull align 4 dereferenceable(4) %b1Bar) #8
+  invoke void @llvm.seh.scope.end()
+          to label %invoke.cont6 unwind label %ehcleanup7
+
+ehcleanup:                                        ; preds = %if.end, %invoke.cont
+  %7 = cleanuppad within none []
+  call void @"??1B1@@QEAA at XZ"(%class.B1* nonnull align 4 dereferenceable(4) %b1Bar) #8 [ "funclet"(token %7) ]
+  cleanupret from %7 unwind label %ehcleanup7
+
+invoke.cont6:                                     ; preds = %invoke.cont5
+  call void @"??1B2@@QEAA at XZ"(%class.B2* nonnull align 4 dereferenceable(4) %b2Bar) #8
+  ret i32 %add
+
+ehcleanup7:                                       ; preds = %invoke.cont5, %ehcleanup, %entry
+  %8 = cleanuppad within none []
+  call void @"??1B2@@QEAA at XZ"(%class.B2* nonnull align 4 dereferenceable(4) %b2Bar) #8 [ "funclet"(token %8) ]
+  cleanupret from %8 unwind to caller
+}
+
+; Function Attrs: nounwind readnone
+declare dso_local void @llvm.seh.scope.begin() #2
+
+declare dso_local i32 @__CxxFrameHandler3(...)
+
+; Function Attrs: nounwind readnone
+declare dso_local void @llvm.seh.scope.end() #2
+
+; Function Attrs: noinline nounwind optnone
+define linkonce_odr dso_local void @"??1B1@@QEAA at XZ"(%class.B1* nonnull align 4 dereferenceable(4) %this) unnamed_addr #3 comdat align 2 {
+entry:
+  %this.addr = alloca %class.B1*, align 8
+  store %class.B1* %this, %class.B1** %this.addr, align 8
+  %this1 = load %class.B1*, %class.B1** %this.addr, align 8
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C at _0N@FMGAAAAM at in?5B1?5Dtor?5?6?$AA@", i64 0, i64 0))
+  ret void
+}
+
+; Function Attrs: noinline nounwind optnone
+define linkonce_odr dso_local void @"??1B2@@QEAA at XZ"(%class.B2* nonnull align 4 dereferenceable(4) %this) unnamed_addr #3 comdat align 2 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+  %this.addr = alloca %class.B2*, align 8
+  store %class.B2* %this, %class.B2** %this.addr, align 8
+  %this1 = load %class.B2*, %class.B2** %this.addr, align 8
+  invoke void @llvm.seh.scope.begin()
+          to label %invoke.cont unwind label %ehcleanup
+
+invoke.cont:                                      ; preds = %entry
+  invoke void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C at _0N@GFONDMMJ at in?5B2?5Dtor?5?6?$AA@", i64 0, i64 0))
+          to label %invoke.cont2 unwind label %ehcleanup
+
+invoke.cont2:                                     ; preds = %invoke.cont
+  invoke void @llvm.seh.scope.end()
+          to label %invoke.cont3 unwind label %ehcleanup
+
+invoke.cont3:                                     ; preds = %invoke.cont2
+  %0 = bitcast %class.B2* %this1 to %class.B1*
+  call void @"??1B1@@QEAA at XZ"(%class.B1* nonnull align 4 dereferenceable(4) %0) #8
+  ret void
+
+ehcleanup:                                        ; preds = %invoke.cont2, %invoke.cont, %entry
+  %1 = cleanuppad within none []
+  %2 = bitcast %class.B2* %this1 to %class.B1*
+  call void @"??1B1@@QEAA at XZ"(%class.B1* nonnull align 4 dereferenceable(4) %2) #8 [ "funclet"(token %1) ]
+  cleanupret from %1 unwind to caller
+}
+
+; Function Attrs: noinline optnone mustprogress
+define dso_local void @"?goo@@YA?AVB1@@H at Z"(%class.B1* noalias sret(%class.B1) align 4 %agg.result, i32 %w) #1 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+  %result.ptr = alloca i8*, align 8
+  %w.addr = alloca i32, align 4
+  %b2ingoo = alloca %class.B2, align 4
+  %0 = bitcast %class.B1* %agg.result to i8*
+  store i8* %0, i8** %result.ptr, align 8
+  store i32 %w, i32* %w.addr, align 4
+  %call = call %class.B2* @"??0B2@@QEAA at XZ"(%class.B2* nonnull align 4 dereferenceable(4) %b2ingoo)
+  invoke void @llvm.seh.scope.begin()
+          to label %invoke.cont unwind label %ehcleanup
+
+invoke.cont:                                      ; preds = %entry
+  %1 = load i32, i32* %w.addr, align 4
+  %2 = bitcast %class.B2* %b2ingoo to %class.B1*
+  %data = getelementptr inbounds %class.B1, %class.B1* %2, i32 0, i32 0
+  %3 = load i32, i32* %data, align 4
+  %add = add nsw i32 %3, %1
+  store i32 %add, i32* %data, align 4
+  %4 = bitcast %class.B2* %b2ingoo to %class.B1*
+  %5 = bitcast %class.B1* %agg.result to i8*
+  %6 = bitcast %class.B1* %4 to i8*
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %5, i8* align 4 %6, i64 4, i1 false)
+  invoke void @llvm.seh.scope.end()
+          to label %invoke.cont1 unwind label %ehcleanup
+
+invoke.cont1:                                     ; preds = %invoke.cont
+  call void @"??1B2@@QEAA at XZ"(%class.B2* nonnull align 4 dereferenceable(4) %b2ingoo) #8
+  ret void
+
+ehcleanup:                                        ; preds = %invoke.cont, %entry
+  %7 = cleanuppad within none []
+  call void @"??1B2@@QEAA at XZ"(%class.B2* nonnull align 4 dereferenceable(4) %b2ingoo) #8 [ "funclet"(token %7) ]
+  cleanupret from %7 unwind to caller
+}
+
+; Function Attrs: noinline optnone
+define linkonce_odr dso_local %class.B2* @"??0B2@@QEAA at XZ"(%class.B2* nonnull returned align 4 dereferenceable(4) %this) unnamed_addr #4 comdat align 2 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+  %this.addr = alloca %class.B2*, align 8
+  store %class.B2* %this, %class.B2** %this.addr, align 8
+  %this1 = load %class.B2*, %class.B2** %this.addr, align 8
+  %0 = bitcast %class.B2* %this1 to %class.B1*
+  %call = call %class.B1* @"??0B1@@QEAA at XZ"(%class.B1* nonnull align 4 dereferenceable(4) %0)
+  invoke void @llvm.seh.scope.begin()
+          to label %invoke.cont unwind label %ehcleanup
+
+invoke.cont:                                      ; preds = %entry
+  %1 = bitcast %class.B2* %this1 to %class.B1*
+  %data = getelementptr inbounds %class.B1, %class.B1* %1, i32 0, i32 0
+  %2 = load i32, i32* %data, align 4
+  %add = add nsw i32 %2, 222
+  %call2 = call i32 @"?foo@@YAHH at Z"(i32 %add)
+  invoke void @llvm.seh.scope.end()
+          to label %invoke.cont3 unwind label %ehcleanup
+
+invoke.cont3:                                     ; preds = %invoke.cont
+  ret %class.B2* %this1
+
+ehcleanup:                                        ; preds = %invoke.cont, %entry
+  %3 = cleanuppad within none []
+  %4 = bitcast %class.B2* %this1 to %class.B1*
+  call void @"??1B1@@QEAA at XZ"(%class.B1* nonnull align 4 dereferenceable(4) %4) #8 [ "funclet"(token %3) ]
+  cleanupret from %3 unwind to caller
+}
+
+; Function Attrs: argmemonly nofree nosync nounwind willreturn
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #5
+
+; Function Attrs: noinline norecurse optnone mustprogress
+define dso_local i32 @main() #6 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+  %retval = alloca i32, align 4
+  %b3inmain = alloca %class.B3, align 4
+  %m = alloca i32, align 4
+  %ref.tmp = alloca %class.B2, align 4
+  %cleanup.cond = alloca i1, align 1
+  %ref.tmp5 = alloca %class.B3, align 4
+  %cleanup.cond9 = alloca i1, align 1
+  %i = alloca i32, align 4
+  %agg.tmp = alloca %class.B2, align 4
+  %agg.tmp28 = alloca %class.B1, align 4
+  %b1fromgoo = alloca %class.B1, align 4
+  store i32 0, i32* %retval, align 4
+  %call = call %class.B3* @"??0B3@@QEAA at XZ"(%class.B3* nonnull align 4 dereferenceable(4) %b3inmain)
+  invoke void @llvm.seh.scope.begin()
+          to label %invoke.cont unwind label %ehcleanup50
+
+invoke.cont:                                      ; preds = %entry
+  %0 = load i32, i32* @"?xxxx@@3HA", align 4
+  %cmp = icmp sgt i32 %0, 1
+  store i1 false, i1* %cleanup.cond, align 1
+  store i1 false, i1* %cleanup.cond9, align 1
+  br i1 %cmp, label %cond.true, label %cond.false
+
+cond.true:                                        ; preds = %invoke.cont
+  %call2 = invoke %class.B2* @"??0B2@@QEAA at XZ"(%class.B2* nonnull align 4 dereferenceable(4) %ref.tmp)
+          to label %invoke.cont1 unwind label %ehcleanup50
+
+invoke.cont1:                                     ; preds = %cond.true
+  invoke void @llvm.seh.scope.begin()
+          to label %invoke.cont3 unwind label %ehcleanup21
+
+invoke.cont3:                                     ; preds = %invoke.cont1
+  store i1 true, i1* %cleanup.cond, align 1
+  %1 = bitcast %class.B2* %ref.tmp to %class.B1*
+  %data = getelementptr inbounds %class.B1, %class.B1* %1, i32 0, i32 0
+  %2 = load i32, i32* %data, align 4
+  %call4 = call i32 @"?foo@@YAHH at Z"(i32 99)
+  %add = add nsw i32 %2, %call4
+  br label %cond.end
+
+cond.false:                                       ; preds = %invoke.cont
+  %call7 = invoke %class.B3* @"??0B3@@QEAA at XZ"(%class.B3* nonnull align 4 dereferenceable(4) %ref.tmp5)
+          to label %invoke.cont6 unwind label %ehcleanup21
+
+invoke.cont6:                                     ; preds = %cond.false
+  invoke void @llvm.seh.scope.begin()
+          to label %invoke.cont8 unwind label %ehcleanup
+
+invoke.cont8:                                     ; preds = %invoke.cont6
+  store i1 true, i1* %cleanup.cond9, align 1
+  %3 = bitcast %class.B3* %ref.tmp5 to %class.B1*
+  %data10 = getelementptr inbounds %class.B1, %class.B1* %3, i32 0, i32 0
+  %4 = load i32, i32* %data10, align 4
+  %call11 = call i32 @"?foo@@YAHH at Z"(i32 88)
+  %add12 = add nsw i32 %4, %call11
+  br label %cond.end
+
+cond.end:                                         ; preds = %invoke.cont8, %invoke.cont3
+  %cond = phi i32 [ %add, %invoke.cont3 ], [ %add12, %invoke.cont8 ]
+  invoke void @llvm.seh.scope.end()
+          to label %invoke.cont13 unwind label %ehcleanup
+
+invoke.cont13:                                    ; preds = %cond.end
+  %cleanup.is_active = load i1, i1* %cleanup.cond9, align 1
+  br i1 %cleanup.is_active, label %cleanup.action, label %cleanup.done
+
+cleanup.action:                                   ; preds = %invoke.cont13
+  call void @"??1B3@@QEAA at XZ"(%class.B3* nonnull align 4 dereferenceable(4) %ref.tmp5) #8
+  br label %cleanup.done
+
+cleanup.done:                                     ; preds = %cleanup.action, %invoke.cont13
+  invoke void @llvm.seh.scope.end()
+          to label %invoke.cont17 unwind label %ehcleanup21
+
+invoke.cont17:                                    ; preds = %cleanup.done
+  %cleanup.is_active18 = load i1, i1* %cleanup.cond, align 1
+  br i1 %cleanup.is_active18, label %cleanup.action19, label %cleanup.done20
+
+cleanup.action19:                                 ; preds = %invoke.cont17
+  call void @"??1B2@@QEAA at XZ"(%class.B2* nonnull align 4 dereferenceable(4) %ref.tmp) #8
+  br label %cleanup.done20
+
+cleanup.done20:                                   ; preds = %cleanup.action19, %invoke.cont17
+  store i32 %cond, i32* %m, align 4
+  %call26 = invoke %class.B2* @"??0B2@@QEAA at XZ"(%class.B2* nonnull align 4 dereferenceable(4) %agg.tmp)
+          to label %invoke.cont25 unwind label %ehcleanup50
+
+invoke.cont25:                                    ; preds = %cleanup.done20
+  invoke void @llvm.seh.scope.begin()
+          to label %invoke.cont27 unwind label %ehcleanup38
+
+invoke.cont27:                                    ; preds = %invoke.cont25
+  %call30 = invoke %class.B1* @"??0B1@@QEAA at XZ"(%class.B1* nonnull align 4 dereferenceable(4) %agg.tmp28)
+          to label %invoke.cont29 unwind label %ehcleanup38
+
+invoke.cont29:                                    ; preds = %invoke.cont27
+  invoke void @llvm.seh.scope.begin()
+          to label %invoke.cont31 unwind label %ehcleanup36
+
+invoke.cont31:                                    ; preds = %invoke.cont29
+  %call32 = call i32 @"?foo@@YAHH at Z"(i32 0)
+  %coerce.dive = getelementptr inbounds %class.B1, %class.B1* %agg.tmp28, i32 0, i32 0
+  %5 = load i32, i32* %coerce.dive, align 4
+  %coerce.dive33 = getelementptr inbounds %class.B2, %class.B2* %agg.tmp, i32 0, i32 0
+  %coerce.dive34 = getelementptr inbounds %class.B1, %class.B1* %coerce.dive33, i32 0, i32 0
+  %6 = load i32, i32* %coerce.dive34, align 4
+  invoke void @llvm.seh.scope.end()
+          to label %invoke.cont35 unwind label %ehcleanup36
+
+invoke.cont35:                                    ; preds = %invoke.cont31
+  invoke void @llvm.seh.scope.end()
+          to label %invoke.cont37 unwind label %ehcleanup38
+
+invoke.cont37:                                    ; preds = %invoke.cont35
+  %call40 = invoke i32 @"?bar@@YAHHVB1@@VB2@@@Z"(i32 %call32, i32 %5, i32 %6)
+          to label %invoke.cont39 unwind label %ehcleanup50
+
+invoke.cont39:                                    ; preds = %invoke.cont37
+  store i32 %call40, i32* %i, align 4
+  %7 = load i32, i32* %i, align 4
+  invoke void @"?goo@@YA?AVB1@@H at Z"(%class.B1* sret(%class.B1) align 4 %b1fromgoo, i32 %7)
+          to label %invoke.cont41 unwind label %ehcleanup50
+
+invoke.cont41:                                    ; preds = %invoke.cont39
+  invoke void @llvm.seh.scope.begin()
+          to label %invoke.cont42 unwind label %ehcleanup48
+
+invoke.cont42:                                    ; preds = %invoke.cont41
+  %8 = load i32, i32* %m, align 4
+  %data43 = getelementptr inbounds %class.B1, %class.B1* %b1fromgoo, i32 0, i32 0
+  %9 = load i32, i32* %data43, align 4
+  %add44 = add nsw i32 %8, %9
+  %10 = bitcast %class.B3* %b3inmain to %class.B1*
+  %data45 = getelementptr inbounds %class.B1, %class.B1* %10, i32 0, i32 0
+  %11 = load i32, i32* %data45, align 4
+  %add46 = add nsw i32 %add44, %11
+  store i32 %add46, i32* %retval, align 4
+  invoke void @llvm.seh.scope.end()
+          to label %invoke.cont47 unwind label %ehcleanup48
+
+ehcleanup:                                        ; preds = %cond.end, %invoke.cont6
+  %12 = cleanuppad within none []
+  %cleanup.is_active14 = load i1, i1* %cleanup.cond9, align 1
+  br i1 %cleanup.is_active14, label %cleanup.action15, label %cleanup.done16
+
+cleanup.action15:                                 ; preds = %ehcleanup
+  call void @"??1B3@@QEAA at XZ"(%class.B3* nonnull align 4 dereferenceable(4) %ref.tmp5) #8 [ "funclet"(token %12) ]
+  br label %cleanup.done16
+
+cleanup.done16:                                   ; preds = %cleanup.action15, %ehcleanup
+  cleanupret from %12 unwind label %ehcleanup21
+
+ehcleanup21:                                      ; preds = %cleanup.done, %cleanup.done16, %cond.false, %invoke.cont1
+  %13 = cleanuppad within none []
+  %cleanup.is_active22 = load i1, i1* %cleanup.cond, align 1
+  br i1 %cleanup.is_active22, label %cleanup.action23, label %cleanup.done24
+
+cleanup.action23:                                 ; preds = %ehcleanup21
+  call void @"??1B2@@QEAA at XZ"(%class.B2* nonnull align 4 dereferenceable(4) %ref.tmp) #8 [ "funclet"(token %13) ]
+  br label %cleanup.done24
+
+cleanup.done24:                                   ; preds = %cleanup.action23, %ehcleanup21
+  cleanupret from %13 unwind label %ehcleanup50
+
+ehcleanup36:                                      ; preds = %invoke.cont31, %invoke.cont29
+  %14 = cleanuppad within none []
+  call void @"??1B1@@QEAA at XZ"(%class.B1* nonnull align 4 dereferenceable(4) %agg.tmp28) #8 [ "funclet"(token %14) ]
+  cleanupret from %14 unwind label %ehcleanup38
+
+ehcleanup38:                                      ; preds = %invoke.cont35, %ehcleanup36, %invoke.cont27, %invoke.cont25
+  %15 = cleanuppad within none []
+  call void @"??1B2@@QEAA at XZ"(%class.B2* nonnull align 4 dereferenceable(4) %agg.tmp) #8 [ "funclet"(token %15) ]
+  cleanupret from %15 unwind label %ehcleanup50
+
+invoke.cont47:                                    ; preds = %invoke.cont42
+  call void @"??1B1@@QEAA at XZ"(%class.B1* nonnull align 4 dereferenceable(4) %b1fromgoo) #8
+  invoke void @llvm.seh.scope.end()
+          to label %invoke.cont49 unwind label %ehcleanup50
+
+ehcleanup48:                                      ; preds = %invoke.cont42, %invoke.cont41
+  %16 = cleanuppad within none []
+  call void @"??1B1@@QEAA at XZ"(%class.B1* nonnull align 4 dereferenceable(4) %b1fromgoo) #8 [ "funclet"(token %16) ]
+  cleanupret from %16 unwind label %ehcleanup50
+
+invoke.cont49:                                    ; preds = %invoke.cont47
+  call void @"??1B3@@QEAA at XZ"(%class.B3* nonnull align 4 dereferenceable(4) %b3inmain) #8
+  %17 = load i32, i32* %retval, align 4
+  ret i32 %17
+
+ehcleanup50:                                      ; preds = %invoke.cont47, %ehcleanup48, %invoke.cont39, %invoke.cont37, %ehcleanup38, %cleanup.done20, %cleanup.done24, %cond.true, %entry
+  %18 = cleanuppad within none []
+  call void @"??1B3@@QEAA at XZ"(%class.B3* nonnull align 4 dereferenceable(4) %b3inmain) #8 [ "funclet"(token %18) ]
+  cleanupret from %18 unwind to caller
+}
+
+; Function Attrs: noinline optnone
+define linkonce_odr dso_local %class.B3* @"??0B3@@QEAA at XZ"(%class.B3* nonnull returned align 4 dereferenceable(4) %this) unnamed_addr #4 comdat align 2 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+  %this.addr = alloca %class.B3*, align 8
+  store %class.B3* %this, %class.B3** %this.addr, align 8
+  %this1 = load %class.B3*, %class.B3** %this.addr, align 8
+  %0 = bitcast %class.B3* %this1 to %class.B2*
+  %call = call %class.B2* @"??0B2@@QEAA at XZ"(%class.B2* nonnull align 4 dereferenceable(4) %0)
+  invoke void @llvm.seh.scope.begin()
+          to label %invoke.cont unwind label %ehcleanup
+
+invoke.cont:                                      ; preds = %entry
+  %1 = bitcast %class.B3* %this1 to %class.B1*
+  %data = getelementptr inbounds %class.B1, %class.B1* %1, i32 0, i32 0
+  %2 = load i32, i32* %data, align 4
+  %add = add nsw i32 %2, 333
+  %call2 = call i32 @"?foo@@YAHH at Z"(i32 %add)
+  invoke void @llvm.seh.scope.end()
+          to label %invoke.cont3 unwind label %ehcleanup
+
+invoke.cont3:                                     ; preds = %invoke.cont
+  ret %class.B3* %this1
+
+ehcleanup:                                        ; preds = %invoke.cont, %entry
+  %3 = cleanuppad within none []
+  %4 = bitcast %class.B3* %this1 to %class.B2*
+  call void @"??1B2@@QEAA at XZ"(%class.B2* nonnull align 4 dereferenceable(4) %4) #8 [ "funclet"(token %3) ]
+  cleanupret from %3 unwind to caller
+}
+
+; Function Attrs: noinline nounwind optnone
+define linkonce_odr dso_local void @"??1B3@@QEAA at XZ"(%class.B3* nonnull align 4 dereferenceable(4) %this) unnamed_addr #3 comdat align 2 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+  %this.addr = alloca %class.B3*, align 8
+  store %class.B3* %this, %class.B3** %this.addr, align 8
+  %this1 = load %class.B3*, %class.B3** %this.addr, align 8
+  invoke void @llvm.seh.scope.begin()
+          to label %invoke.cont unwind label %ehcleanup
+
+invoke.cont:                                      ; preds = %entry
+  invoke void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C at _0N@HCJGCIIK at in?5B3?5Dtor?5?6?$AA@", i64 0, i64 0))
+          to label %invoke.cont2 unwind label %ehcleanup
+
+invoke.cont2:                                     ; preds = %invoke.cont
+  invoke void @llvm.seh.scope.end()
+          to label %invoke.cont3 unwind label %ehcleanup
+
+invoke.cont3:                                     ; preds = %invoke.cont2
+  %0 = bitcast %class.B3* %this1 to %class.B2*
+  call void @"??1B2@@QEAA at XZ"(%class.B2* nonnull align 4 dereferenceable(4) %0) #8
+  ret void
+
+ehcleanup:                                        ; preds = %invoke.cont2, %invoke.cont, %entry
+  %1 = cleanuppad within none []
+  %2 = bitcast %class.B3* %this1 to %class.B2*
+  call void @"??1B2@@QEAA at XZ"(%class.B2* nonnull align 4 dereferenceable(4) %2) #8 [ "funclet"(token %1) ]
+  cleanupret from %1 unwind to caller
+}
+
+; Function Attrs: noinline nounwind optnone
+define linkonce_odr dso_local %class.B1* @"??0B1@@QEAA at XZ"(%class.B1* nonnull returned align 4 dereferenceable(4) %this) unnamed_addr #3 comdat align 2 {
+entry:
+  %this.addr = alloca %class.B1*, align 8
+  store %class.B1* %this, %class.B1** %this.addr, align 8
+  %this1 = load %class.B1*, %class.B1** %this.addr, align 8
+  %data = getelementptr inbounds %class.B1, %class.B1* %this1, i32 0, i32 0
+  store i32 90, i32* %data, align 4
+  %data2 = getelementptr inbounds %class.B1, %class.B1* %this1, i32 0, i32 0
+  %0 = load i32, i32* %data2, align 4
+  %add = add nsw i32 %0, 111
+  %call = call i32 @"?foo@@YAHH at Z"(i32 %add)
+  ret %class.B1* %this1
+}
+
+declare dso_local void @"?printf@@YAXZZ"(...) #7
+
+attributes #0 = { noinline nounwind optnone mustprogress "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" }
+attributes #1 = { noinline optnone mustprogress "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" }
+attributes #2 = { nounwind readnone }
+attributes #3 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" }
+attributes #4 = { noinline optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" }
+attributes #5 = { argmemonly nofree nosync nounwind willreturn }
+attributes #6 = { noinline norecurse optnone mustprogress "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" }
+attributes #7 = { "frame-pointer"="none" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" }
+attributes #8 = { nounwind }
+
+!llvm.module.flags = !{!0, !1}
+
+!0 = !{i32 1, !"wchar_size", i32 2}
+!1 = !{i32 2, !"eh-asynch", i32 1}

diff  --git a/llvm/test/CodeGen/X86/windows-seh-EHa-CppDtors01.ll b/llvm/test/CodeGen/X86/windows-seh-EHa-CppDtors01.ll
new file mode 100644
index 000000000000..8981cebcf499
--- /dev/null
+++ b/llvm/test/CodeGen/X86/windows-seh-EHa-CppDtors01.ll
@@ -0,0 +1,255 @@
+; RUN: llc -verify-machineinstrs < %s | FileCheck %s
+
+; CHECK-LABEL: "$cppxdata$?crash@@YAXH at Z":
+; CHECK:	.long	("$stateUnwindMap$?crash@@YAXH at Z")
+; CHECK:	.long	("$ip2state$?crash@@YAXH at Z")
+
+; CHECK-LABEL: "$stateUnwindMap$?crash@@YAXH at Z":
+; CHECK:	.long	-1 
+; CHECK:	.long	"?dtor$
+; CHECK:	.long	0 
+; CHECK:	.long	"?dtor$
+; CHECK:	.long	1
+; CHECK:	.long	"?dtor$
+
+; CHECK-LABEL: "$ip2state$?crash@@YAXH at Z":
+; CHECK-NEXT:	.long	.Lfunc_begin0 at IMGREL
+; CHECK-NEXT:	.long	-1                  
+; CHECK-NEXT:	.long	.Ltmp     
+; CHECK-NEXT:	.long	0                   
+; CHECK-NEXT:	.long	.Ltmp     
+; CHECK-NEXT:	.long	1                   
+; CHECK-NEXT:	.long	.Ltmp
+; CHECK-NEXT:	.long	2                   
+; CHECK-NEXT:	.long	.Ltmp
+; CHECK-NEXT:	.long	1                   
+; CHECK-NEXT:	.long	.Ltmp
+; CHECK-NEXT:	.long	0                   
+; CHECK-NEXT:	.long	.Ltmp
+; CHECK-NEXT:	.long	-1                  
+
+; ModuleID = 'windows-seh-EHa-CppDtors01.cpp'
+source_filename = "windows-seh-EHa-CppDtors01.cpp"
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-windows-msvc"
+
+%struct.A = type { i8 }
+%struct.B = type { i8 }
+%struct.C = type { i8 }
+
+$"??_C at _0CM@KAOHJHDK@?5Test?5CPP?5unwind?3?5in?5catch?5handl@" = comdat any
+
+$"??_C at _0N@FCCEEGKL@?5in?5C?5dtor?5?6?$AA@" = comdat any
+
+$"??_C at _0N@EFFPFCOI@?5in?5B?5dtor?5?6?$AA@" = comdat any
+
+$"??_C at _0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@" = comdat any
+
+@"?g@@3HA" = dso_local global i32 0, align 4
+@"??_C at _0CM@KAOHJHDK@?5Test?5CPP?5unwind?3?5in?5catch?5handl@" = linkonce_odr dso_local unnamed_addr constant [44 x i8] c" Test CPP unwind: in catch handler i = %d \0A\00", comdat, align 1
+@"??_C at _0N@FCCEEGKL@?5in?5C?5dtor?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [13 x i8] c" in C dtor \0A\00", comdat, align 1
+@"??_C at _0N@EFFPFCOI@?5in?5B?5dtor?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [13 x i8] c" in B dtor \0A\00", comdat, align 1
+@"??_C at _0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [13 x i8] c" in A dtor \0A\00", comdat, align 1
+
+; Function Attrs: noinline optnone
+define dso_local void @"?crash@@YAXH at Z"(i32 %i) #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+  %i.addr = alloca i32, align 4
+  %ObjA = alloca %struct.A, align 1
+  %ObjB = alloca %struct.B, align 1
+  %ObjC = alloca %struct.C, align 1
+  store i32 %i, i32* %i.addr, align 4
+  invoke void @llvm.seh.scope.begin()
+          to label %invoke.cont unwind label %ehcleanup13
+
+invoke.cont:                                      ; preds = %entry
+  %0 = load i32, i32* %i.addr, align 4
+  %cmp = icmp eq i32 %0, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %invoke.cont
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %invoke.cont
+  invoke void @llvm.seh.scope.begin()
+          to label %invoke.cont1 unwind label %ehcleanup11
+
+invoke.cont1:                                     ; preds = %if.end
+  %1 = load i32, i32* %i.addr, align 4
+  %cmp2 = icmp eq i32 %1, 1
+  br i1 %cmp2, label %if.then3, label %if.end4
+
+if.then3:                                         ; preds = %invoke.cont1
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4
+  br label %if.end4
+
+if.end4:                                          ; preds = %if.then3, %invoke.cont1
+  invoke void @llvm.seh.scope.begin()
+          to label %invoke.cont5 unwind label %ehcleanup
+
+invoke.cont5:                                     ; preds = %if.end4
+  %2 = load i32, i32* %i.addr, align 4
+  %cmp6 = icmp eq i32 %2, 2
+  br i1 %cmp6, label %if.then7, label %if.end8
+
+if.then7:                                         ; preds = %invoke.cont5
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4
+  br label %if.end8
+
+if.end8:                                          ; preds = %if.then7, %invoke.cont5
+  invoke void @llvm.seh.scope.end()
+          to label %invoke.cont9 unwind label %ehcleanup
+
+invoke.cont9:                                     ; preds = %if.end8
+  call void @"??1C@?1??crash@@YAXH at Z@QEAA at XZ"(%struct.C* %ObjC) #6
+  invoke void @llvm.seh.scope.end()
+          to label %invoke.cont10 unwind label %ehcleanup11
+
+invoke.cont10:                                    ; preds = %invoke.cont9
+  call void @"??1B@?1??crash@@YAXH at Z@QEAA at XZ"(%struct.B* %ObjB) #6
+  invoke void @llvm.seh.scope.end()
+          to label %invoke.cont12 unwind label %ehcleanup13
+
+invoke.cont12:                                    ; preds = %invoke.cont10
+  call void @"??1A@?1??crash@@YAXH at Z@QEAA at XZ"(%struct.A* %ObjA) #6
+  ret void
+
+ehcleanup:                                        ; preds = %if.end8, %if.end4
+  %3 = cleanuppad within none []
+  call void @"??1C@?1??crash@@YAXH at Z@QEAA at XZ"(%struct.C* %ObjC) #6 [ "funclet"(token %3) ]
+  cleanupret from %3 unwind label %ehcleanup11
+
+ehcleanup11:                                      ; preds = %invoke.cont9, %ehcleanup, %if.end
+  %4 = cleanuppad within none []
+  call void @"??1B@?1??crash@@YAXH at Z@QEAA at XZ"(%struct.B* %ObjB) #6 [ "funclet"(token %4) ]
+  cleanupret from %4 unwind label %ehcleanup13
+
+ehcleanup13:                                      ; preds = %invoke.cont10, %ehcleanup11, %entry
+  %5 = cleanuppad within none []
+  call void @"??1A@?1??crash@@YAXH at Z@QEAA at XZ"(%struct.A* %ObjA) #6 [ "funclet"(token %5) ]
+  cleanupret from %5 unwind to caller
+}
+
+; Function Attrs: nounwind readnone
+declare dso_local void @llvm.seh.scope.begin() #1
+
+declare dso_local i32 @__CxxFrameHandler3(...)
+
+; Function Attrs: nounwind readnone
+declare dso_local void @llvm.seh.scope.end() #1
+
+; Function Attrs: noinline nounwind optnone
+define internal void @"??1C@?1??crash@@YAXH at Z@QEAA at XZ"(%struct.C* %this) unnamed_addr #2 align 2 {
+entry:
+  %this.addr = alloca %struct.C*, align 8
+  store %struct.C* %this, %struct.C** %this.addr, align 8
+  %this1 = load %struct.C*, %struct.C** %this.addr, align 8
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C at _0N@FCCEEGKL@?5in?5C?5dtor?5?6?$AA@", i64 0, i64 0))
+  ret void
+}
+
+; Function Attrs: noinline nounwind optnone
+define internal void @"??1B@?1??crash@@YAXH at Z@QEAA at XZ"(%struct.B* %this) unnamed_addr #2 align 2 {
+entry:
+  %this.addr = alloca %struct.B*, align 8
+  store %struct.B* %this, %struct.B** %this.addr, align 8
+  %this1 = load %struct.B*, %struct.B** %this.addr, align 8
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C at _0N@EFFPFCOI@?5in?5B?5dtor?5?6?$AA@", i64 0, i64 0))
+  ret void
+}
+
+; Function Attrs: noinline nounwind optnone
+define internal void @"??1A@?1??crash@@YAXH at Z@QEAA at XZ"(%struct.A* %this) unnamed_addr #2 align 2 {
+entry:
+  %this.addr = alloca %struct.A*, align 8
+  store %struct.A* %this, %struct.A** %this.addr, align 8
+  %this1 = load %struct.A*, %struct.A** %this.addr, align 8
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C at _0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@", i64 0, i64 0))
+  ret void
+}
+
+; Function Attrs: noinline norecurse optnone
+define dso_local i32 @main() #3 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) {
+entry:
+  %retval = alloca i32, align 4
+  %i = alloca i32, align 4
+  %__exception_code = alloca i32, align 4
+  store i32 0, i32* %retval, align 4
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %cmp = icmp slt i32 %0, 3
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  invoke void @llvm.seh.try.begin()
+          to label %invoke.cont unwind label %catch.dispatch
+
+invoke.cont:                                      ; preds = %for.body
+  %1 = load volatile i32, i32* %i, align 4
+  invoke void @"?crash@@YAXH at Z"(i32 %1) #7
+          to label %invoke.cont1 unwind label %catch.dispatch
+
+invoke.cont1:                                     ; preds = %invoke.cont
+  invoke void @llvm.seh.try.end()
+          to label %invoke.cont2 unwind label %catch.dispatch
+
+catch.dispatch:                                   ; preds = %invoke.cont1, %invoke.cont, %for.body
+  %2 = catchswitch within none [label %__except] unwind to caller
+
+__except:                                         ; preds = %catch.dispatch
+  %3 = catchpad within %2 [i8* null]
+  catchret from %3 to label %__except3
+
+__except3:                                        ; preds = %__except
+  %4 = call i32 @llvm.eh.exceptioncode(token %3)
+  store i32 %4, i32* %__exception_code, align 4
+  %5 = load i32, i32* %i, align 4
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([44 x i8], [44 x i8]* @"??_C at _0CM@KAOHJHDK@?5Test?5CPP?5unwind?3?5in?5catch?5handl@", i64 0, i64 0), i32 %5)
+  br label %__try.cont
+
+__try.cont:                                       ; preds = %__except3, %invoke.cont2
+  br label %for.inc
+
+for.inc:                                          ; preds = %__try.cont
+  %6 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %6, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+invoke.cont2:                                     ; preds = %invoke.cont1
+  br label %__try.cont
+
+for.end:                                          ; preds = %for.cond
+  ret i32 0
+}
+
+; Function Attrs: nounwind willreturn
+declare dso_local void @llvm.seh.try.begin() #4
+
+declare dso_local i32 @__C_specific_handler(...)
+
+; Function Attrs: nounwind willreturn
+declare dso_local void @llvm.seh.try.end() #4
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.eh.exceptioncode(token) #1
+
+declare dso_local void @"?printf@@YAXZZ"(...) #5
+
+attributes #0 = { noinline optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #3 = { noinline norecurse optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #4 = { nounwind willreturn }
+attributes #5 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #6 = { nounwind }
+attributes #7 = { noinline }
+
+!llvm.module.flags = !{!0, !1}
+
+!0 = !{i32 1, !"wchar_size", i32 2}
+!1 = !{i32 2, !"eh-asynch", i32 1}

diff  --git a/llvm/test/CodeGen/X86/windows-seh-EHa-TryInFinally.ll b/llvm/test/CodeGen/X86/windows-seh-EHa-TryInFinally.ll
new file mode 100644
index 000000000000..4fed37564924
--- /dev/null
+++ b/llvm/test/CodeGen/X86/windows-seh-EHa-TryInFinally.ll
@@ -0,0 +1,224 @@
+; RUN: llc -verify-machineinstrs < %s | FileCheck %s
+
+; CHECK-LABEL: "?fin$0 at 0@main@@"
+; CHECK:      .seh_handlerdata
+; CHECK:      .set ".L?fin$0 at 0@main@@$parent_frame_offset", 48
+; CHECK-NEXT:        .long   (.Llsda_end1-.Llsda_begin1)/16 
+; CHECK-NEXT: .Llsda_begin1:
+; CHECK-NEXT:        .long   .Ltmp
+; CHECK-NEXT:        .long   .Ltmp
+; CHECK-NEXT:        .long   "?dtor$
+; CHECK-NEXT:        .long   0
+; CHECK-NEXT: .Llsda_end1:
+
+; ModuleID = 'windows-seh-EHa-TryInFinally.cpp'
+source_filename = "windows-seh-EHa-TryInFinally.cpp"
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-windows-msvc"
+
+$"??_C at _0CI@MDFPIOJJ@?5?9?9?9?5Test?5_Try?5in?5_finally?5?9?9?9?5i@" = comdat any
+
+$"??_C at _0BN@HHKJHLBE@?5?5In?5Inner?5_finally?5i?5?$DN?5?$CFd?5?6?$AA@" = comdat any
+
+$"??_C at _0BN@HAIIIOKI@?5?5In?5outer?5_finally?5i?5?$DN?5?$CFd?5?6?$AA@" = comdat any
+
+$"??_C at _0BJ@OJMMAGCD@?5?5In?5outer?5_try?5i?5?$DN?5?$CFd?5?6?$AA@" = comdat any
+
+$"??_C at _0CG@ENDJHCGA@?5?9?9?9?5In?5outer?5except?5handler?5i?5?$DN@" = comdat any
+
+@"??_C at _0CI@MDFPIOJJ@?5?9?9?9?5Test?5_Try?5in?5_finally?5?9?9?9?5i@" = linkonce_odr dso_local unnamed_addr constant [40 x i8] c" --- Test _Try in _finally --- i = %d \0A\00", comdat, align 1
+@"??_C at _0BN@HHKJHLBE@?5?5In?5Inner?5_finally?5i?5?$DN?5?$CFd?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [29 x i8] c"  In Inner _finally i = %d \0A\00", comdat, align 1
+@"??_C at _0BN@HAIIIOKI@?5?5In?5outer?5_finally?5i?5?$DN?5?$CFd?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [29 x i8] c"  In outer _finally i = %d \0A\00", comdat, align 1
+@"??_C at _0BJ@OJMMAGCD@?5?5In?5outer?5_try?5i?5?$DN?5?$CFd?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [25 x i8] c"  In outer _try i = %d \0A\00", comdat, align 1
+@"??_C at _0CG@ENDJHCGA@?5?9?9?9?5In?5outer?5except?5handler?5i?5?$DN@" = linkonce_odr dso_local unnamed_addr constant [38 x i8] c" --- In outer except handler i = %d \0A\00", comdat, align 1
+
+; Function Attrs: noinline norecurse optnone
+define dso_local i32 @main() #0 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) {
+entry:
+  %retval = alloca i32, align 4
+  %i = alloca i32, align 4
+  %__exception_code = alloca i32, align 4
+  call void (...) @llvm.localescape(i32* %i)
+  store i32 0, i32* %retval, align 4
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %cmp = icmp slt i32 %0, 3
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %1 = load i32, i32* %i, align 4
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([40 x i8], [40 x i8]* @"??_C at _0CI@MDFPIOJJ@?5?9?9?9?5Test?5_Try?5in?5_finally?5?9?9?9?5i@", i64 0, i64 0), i32 %1)
+  invoke void @llvm.seh.try.begin()
+          to label %invoke.cont unwind label %catch.dispatch
+
+invoke.cont:                                      ; preds = %for.body
+  invoke void @llvm.seh.try.begin()
+          to label %invoke.cont1 unwind label %ehcleanup
+
+invoke.cont1:                                     ; preds = %invoke.cont
+  %2 = load volatile i32, i32* %i, align 4
+  invoke void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @"??_C at _0BJ@OJMMAGCD@?5?5In?5outer?5_try?5i?5?$DN?5?$CFd?5?6?$AA@", i64 0, i64 0), i32 %2) #6
+          to label %invoke.cont2 unwind label %ehcleanup
+
+invoke.cont2:                                     ; preds = %invoke.cont1
+  %3 = load volatile i32, i32* %i, align 4
+  %cmp3 = icmp eq i32 %3, 0
+  br i1 %cmp3, label %if.then, label %if.end
+
+if.then:                                          ; preds = %invoke.cont2
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %invoke.cont2
+  invoke void @llvm.seh.try.end()
+          to label %invoke.cont4 unwind label %ehcleanup
+
+invoke.cont4:                                     ; preds = %if.end
+  %4 = call i8* @llvm.localaddress()
+  invoke void @"?fin$0 at 0@main@@"(i8 0, i8* %4) #6
+          to label %invoke.cont5 unwind label %catch.dispatch
+
+invoke.cont5:                                     ; preds = %invoke.cont4
+  invoke void @llvm.seh.try.end()
+          to label %invoke.cont7 unwind label %catch.dispatch
+
+catch.dispatch:                                   ; preds = %invoke.cont5, %invoke.cont6, %ehcleanup, %invoke.cont4, %for.body
+  %5 = catchswitch within none [label %__except] unwind to caller
+
+__except:                                         ; preds = %catch.dispatch
+  %6 = catchpad within %5 [i8* null]
+  catchret from %6 to label %__except8
+
+__except8:                                        ; preds = %__except
+  %7 = call i32 @llvm.eh.exceptioncode(token %6)
+  store i32 %7, i32* %__exception_code, align 4
+  %8 = load i32, i32* %i, align 4
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([38 x i8], [38 x i8]* @"??_C at _0CG@ENDJHCGA@?5?9?9?9?5In?5outer?5except?5handler?5i?5?$DN@", i64 0, i64 0), i32 %8)
+  br label %__try.cont
+
+__try.cont:                                       ; preds = %__except8, %invoke.cont7
+  br label %for.inc
+
+for.inc:                                          ; preds = %__try.cont
+  %9 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %9, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+invoke.cont7:                                     ; preds = %invoke.cont5
+  br label %__try.cont
+
+ehcleanup:                                        ; preds = %if.end, %invoke.cont1, %invoke.cont
+  %10 = cleanuppad within none []
+  %11 = call i8* @llvm.localaddress()
+  invoke void @"?fin$0 at 0@main@@"(i8 1, i8* %11) #6 [ "funclet"(token %10) ]
+          to label %invoke.cont6 unwind label %catch.dispatch
+
+invoke.cont6:                                     ; preds = %ehcleanup
+  cleanupret from %10 unwind label %catch.dispatch
+
+for.end:                                          ; preds = %for.cond
+  ret i32 0
+}
+
+declare dso_local void @"?printf@@YAXZZ"(...) #1
+
+; Function Attrs: nounwind willreturn
+declare dso_local void @llvm.seh.try.begin() #2
+
+declare dso_local i32 @__C_specific_handler(...)
+
+; Function Attrs: noinline
+define internal void @"?fin$0 at 0@main@@"(i8 %abnormal_termination, i8* %frame_pointer) #3 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) {
+entry:
+  %frame_pointer.addr = alloca i8*, align 8
+  %abnormal_termination.addr = alloca i8, align 1
+  %0 = call i8* @llvm.localrecover(i8* bitcast (i32 ()* @main to i8*), i8* %frame_pointer, i32 0)
+  %i = bitcast i8* %0 to i32*
+  store i8* %frame_pointer, i8** %frame_pointer.addr, align 8
+  store i8 %abnormal_termination, i8* %abnormal_termination.addr, align 1
+  invoke void @llvm.seh.try.begin()
+          to label %invoke.cont unwind label %ehcleanup
+
+invoke.cont:                                      ; preds = %entry
+  %1 = load volatile i32, i32* %i, align 4
+  invoke void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([29 x i8], [29 x i8]* @"??_C at _0BN@HAIIIOKI@?5?5In?5outer?5_finally?5i?5?$DN?5?$CFd?5?6?$AA@", i64 0, i64 0), i32 %1) #6
+          to label %invoke.cont1 unwind label %ehcleanup
+
+invoke.cont1:                                     ; preds = %invoke.cont
+  %2 = load volatile i32, i32* %i, align 4
+  %cmp = icmp eq i32 %2, 1
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %invoke.cont1
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %invoke.cont1
+  invoke void @llvm.seh.try.end()
+          to label %invoke.cont2 unwind label %ehcleanup
+
+invoke.cont2:                                     ; preds = %if.end
+  call void @"?fin$1 at 0@main@@"(i8 0, i8* %frame_pointer)
+  ret void
+
+ehcleanup:                                        ; preds = %if.end, %invoke.cont, %entry
+  %3 = cleanuppad within none []
+  call void @"?fin$1 at 0@main@@"(i8 1, i8* %frame_pointer) [ "funclet"(token %3) ]
+  cleanupret from %3 unwind to caller
+}
+
+; Function Attrs: nounwind readnone
+declare i8* @llvm.localrecover(i8*, i8*, i32 immarg) #4
+
+; Function Attrs: noinline
+define internal void @"?fin$1 at 0@main@@"(i8 %abnormal_termination, i8* %frame_pointer) #3 {
+entry:
+  %frame_pointer.addr = alloca i8*, align 8
+  %abnormal_termination.addr = alloca i8, align 1
+  %0 = call i8* @llvm.localrecover(i8* bitcast (i32 ()* @main to i8*), i8* %frame_pointer, i32 0)
+  %i = bitcast i8* %0 to i32*
+  store i8* %frame_pointer, i8** %frame_pointer.addr, align 8
+  store i8 %abnormal_termination, i8* %abnormal_termination.addr, align 1
+  %1 = load i32, i32* %i, align 4
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([29 x i8], [29 x i8]* @"??_C at _0BN@HHKJHLBE@?5?5In?5Inner?5_finally?5i?5?$DN?5?$CFd?5?6?$AA@", i64 0, i64 0), i32 %1)
+  %2 = load i32, i32* %i, align 4
+  %cmp = icmp eq i32 %2, 2
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %entry
+  ret void
+}
+
+; Function Attrs: nounwind willreturn
+declare dso_local void @llvm.seh.try.end() #2
+
+; Function Attrs: nounwind readnone
+declare i8* @llvm.localaddress() #4
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.eh.exceptioncode(token) #4
+
+; Function Attrs: nounwind
+declare void @llvm.localescape(...) #5
+
+attributes #0 = { noinline norecurse optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind willreturn }
+attributes #3 = { noinline "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #4 = { nounwind readnone }
+attributes #5 = { nounwind }
+attributes #6 = { noinline }
+
+!llvm.module.flags = !{!0, !1}
+
+!0 = !{i32 1, !"wchar_size", i32 2}
+!1 = !{i32 2, !"eh-asynch", i32 1}
+


        


More information about the llvm-commits mailing list