Reland "[Windows SEH]: HARDWARE EXCEPTION HANDLING (MSVC -EHa) - Part 2"
authorPhoebe Wang <phoebe.wang@intel.com>
Wed, 29 Mar 2023 00:20:14 +0000 (08:20 +0800)
committerPhoebe Wang <phoebe.wang@intel.com>
Wed, 29 Mar 2023 00:59:56 +0000 (08:59 +0800)
This reverts commit db6a979ae82410e42430e47afa488936ba8e3025.

Reland D102817 without any change. The previous revert was a mistake.

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

15 files changed:
llvm/include/llvm/CodeGen/SelectionDAGISel.h
llvm/include/llvm/CodeGen/WinEHFuncInfo.h
llvm/include/llvm/IR/BasicBlock.h
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
llvm/lib/IR/EHPersonalities.cpp
llvm/test/CodeGen/X86/windows-seh-EHa-CppCatchDotDotDot.ll [new file with mode: 0644]
llvm/test/CodeGen/X86/windows-seh-EHa-CppCondiTemps.ll [new file with mode: 0644]
llvm/test/CodeGen/X86/windows-seh-EHa-CppDtors01.ll [new file with mode: 0644]
llvm/test/CodeGen/X86/windows-seh-EHa-TryInFinally.ll [new file with mode: 0644]

index b7c5bec..6c0b2cf 100644 (file)
@@ -337,6 +337,9 @@ private:
   /// 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);
 
index f098316..c007d46 100644 (file)
@@ -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
index 71d9ada..4e765da 100644 (file)
@@ -213,6 +213,15 @@ public:
         .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.
index c8a88a1..47623e6 100644 (file)
@@ -1627,6 +1627,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) {
@@ -1665,10 +1666,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);
index 7a80043..6bfb5a6 100644 (file)
@@ -762,7 +762,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;
index d5bf62c..b5ac90c 100644 (file)
@@ -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;
index 1abbe9b..1107da1 100644 (file)
@@ -2971,6 +2971,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.
@@ -2995,6 +2996,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:
index 8d1cc04..bdbf32a 100644 (file)
@@ -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"
@@ -1292,6 +1293,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.
@@ -1649,6 +1687,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();
index e97f640..d6d4af0 100644 (file)
@@ -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;
index 63d363e..5e900e6 100644 (file)
@@ -205,6 +205,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))
index 27c8897..afbb2bb 100644 (file)
@@ -12,6 +12,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"
 #include "llvm/TargetParser/Triple.h"
@@ -91,7 +92,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/test/CodeGen/X86/windows-seh-EHa-CppCatchDotDotDot.ll b/llvm/test/CodeGen/X86/windows-seh-EHa-CppCatchDotDotDot.ll
new file mode 100644 (file)
index 0000000..2b09c01
--- /dev/null
@@ -0,0 +1,290 @@
+; RUN: llc -verify-machineinstrs < %s | FileCheck %s\r
+\r
+; CHECK-LABEL: "$cppxdata$?crash@@YAXH@Z":\r
+; CHECK:       .long   ("$stateUnwindMap$?crash@@YAXH@Z")\r
+; CHECK:        .long   ("$tryMap$?crash@@YAXH@Z")@IMGREL # TryBlockMap\r
+; CHECK-NEXT:   .long   6                       # IPMapEntries\r
+; CHECK-NEXT:  .long   ("$ip2state$?crash@@YAXH@Z")\r
+\r
+; CHECK-LABEL: "$stateUnwindMap$?crash@@YAXH@Z":\r
+; CHECK-NEXT:        .long   -1                \r
+; CHECK-NEXT:        .long   0                 \r
+; CHECK-NEXT:        .long   0                 \r
+; CHECK-NEXT:        .long   "?dtor$\r
+; CHECK-NEXT:        .long   -1                \r
+; CHECK-NEXT:        .long   0                 \r
+\r
+; CHECK-LABEL: "$tryMap$?crash@@YAXH@Z":\r
+; CHECK-NEXT:        .long   0             \r
+; CHECK-NEXT:        .long   1             \r
+; CHECK-NEXT:        .long   2             \r
+; CHECK-NEXT:        .long   1             \r
+; CHECK-NEXT:        .long   ("$handlerMap$\r
+\r
+; CHECK:       "$handlerMap$0$?crash@@YAXH@Z"\r
+; CHECK-NEXT:        .long   0             \r
+; CHECK-NEXT:        .long   0             \r
+; CHECK-NEXT:        .long   0             \r
+; CHECK-NEXT:        .long   "?catch$ \r
+\r
+; CHECK-LABEL: "$ip2state$?crash@@YAXH@Z":\r
+; CHECK-NEXT:  .long   .Lfunc_begin0@IMGREL\r
+; CHECK-NEXT:  .long   -1                  \r
+; CHECK-NEXT:  .long   .Ltmp     \r
+; CHECK-NEXT:  .long   0                   \r
+; CHECK-NEXT:  .long   .Ltmp     \r
+; CHECK-NEXT:  .long   1                   \r
+; CHECK-NEXT:  .long   .Ltmp\r
+; CHECK-NEXT:  .long   0                  \r
+; CHECK-NEXT:  .long   .Ltmp\r
+; CHECK-NEXT:  .long   -1                                  \r
+; CHECK-NEXT:  .long   "?catch$\r
+; CHECK-NEXT:  .long   2                  \r
+\r
+; ModuleID = 'windows-seh-EHa-CppCatchDotDotDot.cpp'\r
+source_filename = "windows-seh-EHa-CppCatchDotDotDot.cpp"\r
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"\r
+target triple = "x86_64-unknown-windows-msvc"\r
+\r
+%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }\r
+%eh.CatchableType = type { i32, i32, i32, i32, i32, i32, i32 }\r
+%eh.CatchableTypeArray.1 = type { i32, [1 x i32] }\r
+%eh.ThrowInfo = type { i32, i32, i32, i32 }\r
+%struct.A = type { i8 }\r
+\r
+$"??_C@_0BJ@EIKFKKLB@?5in?5catch?$CI?4?4?4?$CJ?5funclet?5?6?$AA@" = comdat any\r
+\r
+$"??_R0H@8" = comdat any\r
+\r
+$"_CT??_R0H@84" = comdat any\r
+\r
+$_CTA1H = comdat any\r
+\r
+$_TI1H = comdat any\r
+\r
+$"??_C@_0CN@MKCAOFNA@?5Test?5CPP?5unwind?3?5in?5except?5hand@" = comdat any\r
+\r
+$"??_C@_0N@LJHFFAKD@?5in?5A?5ctor?5?6?$AA@" = comdat any\r
+\r
+$"??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@" = comdat any\r
+\r
+@"?pt1@@3PEAHEA" = dso_local global i32* null, align 8\r
+@"?pt2@@3PEAHEA" = dso_local global i32* null, align 8\r
+@"?pt3@@3PEAHEA" = dso_local global i32* null, align 8\r
+@"?g@@3HA" = dso_local global i32 0, align 4\r
+@"??_C@_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\r
+@"??_7type_info@@6B@" = external constant i8*\r
+@"??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat\r
+@__ImageBase = external dso_local constant i8\r
+@"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"??_R0H@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 4, i32 0 }, section ".xdata", comdat\r
+@_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@84" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat\r
+@_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\r
+@"??_C@_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\r
+@"??_C@_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\r
+@"??_C@_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\r
+\r
+; Function Attrs: noinline nounwind optnone\r
+define dso_local void @"?foo@@YAXXZ"() #0 {\r
+entry:\r
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4\r
+  ret void\r
+}\r
+\r
+; Function Attrs: noinline optnone\r
+define dso_local void @"?crash@@YAXH@Z"(i32 %i) #1 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {\r
+entry:\r
+  %i.addr = alloca i32, align 4\r
+  %ObjA = alloca %struct.A, align 1\r
+  %tmp = alloca i32, align 4\r
+  store i32 %i, i32* %i.addr, align 4\r
+  %0 = load i32, i32* %i.addr, align 4\r
+  store i32 %0, i32* @"?g@@3HA", align 4\r
+  invoke void @llvm.seh.try.begin()\r
+          to label %invoke.cont unwind label %catch.dispatch\r
+\r
+invoke.cont:                                      ; preds = %entry\r
+  %call = invoke %struct.A* @"??0A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* %ObjA)\r
+          to label %invoke.cont1 unwind label %catch.dispatch\r
+\r
+invoke.cont1:                                     ; preds = %invoke.cont\r
+  invoke void @llvm.seh.scope.begin()\r
+          to label %invoke.cont2 unwind label %ehcleanup\r
+\r
+invoke.cont2:                                     ; preds = %invoke.cont1\r
+  %1 = load i32, i32* %i.addr, align 4\r
+  %cmp = icmp eq i32 %1, 1\r
+  br i1 %cmp, label %if.then, label %if.end\r
+\r
+if.then:                                          ; preds = %invoke.cont2\r
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4\r
+  br label %if.end\r
+\r
+if.end:                                           ; preds = %if.then, %invoke.cont2\r
+  invoke void @llvm.seh.scope.end()\r
+          to label %invoke.cont3 unwind label %ehcleanup\r
+\r
+invoke.cont3:                                     ; preds = %if.end\r
+  call void @"??1A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* %ObjA) #6\r
+  br label %try.cont\r
+\r
+ehcleanup:                                        ; preds = %if.end, %invoke.cont1\r
+  %2 = cleanuppad within none []\r
+  call void @"??1A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* %ObjA) #6 [ "funclet"(token %2) ]\r
+  cleanupret from %2 unwind label %catch.dispatch\r
+\r
+catch.dispatch:                                   ; preds = %ehcleanup, %invoke.cont, %entry\r
+  %3 = catchswitch within none [label %catch] unwind to caller\r
+\r
+catch:                                            ; preds = %catch.dispatch\r
+  %4 = catchpad within %3 [i8* null, i32 0, i8* null]\r
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @"??_C@_0BJ@EIKFKKLB@?5in?5catch?$CI?4?4?4?$CJ?5funclet?5?6?$AA@", i64 0, i64 0)) [ "funclet"(token %4) ]\r
+  %5 = load i32, i32* %i.addr, align 4\r
+  %cmp4 = icmp eq i32 %5, 1\r
+  br i1 %cmp4, label %if.then5, label %if.end6\r
+\r
+if.then5:                                         ; preds = %catch\r
+  %6 = load i32, i32* %i.addr, align 4\r
+  store i32 %6, i32* %tmp, align 4\r
+  %7 = bitcast i32* %tmp to i8*\r
+  call void @_CxxThrowException(i8* %7, %eh.ThrowInfo* @_TI1H) #7 [ "funclet"(token %4) ]\r
+  unreachable\r
+\r
+if.end6:                                          ; preds = %catch\r
+  catchret from %4 to label %catchret.dest\r
+\r
+catchret.dest:                                    ; preds = %if.end6\r
+  br label %try.cont\r
+\r
+try.cont:                                         ; preds = %catchret.dest, %invoke.cont3\r
+  ret void\r
+}\r
+\r
+; Function Attrs: nounwind willreturn\r
+declare dso_local void @llvm.seh.try.begin() #2\r
+\r
+declare dso_local i32 @__CxxFrameHandler3(...)\r
+\r
+; Function Attrs: noinline optnone\r
+define internal %struct.A* @"??0A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* returned %this) unnamed_addr #1 align 2 {\r
+entry:\r
+  %retval = alloca %struct.A*, align 8\r
+  %this.addr = alloca %struct.A*, align 8\r
+  store %struct.A* %this, %struct.A** %this.addr, align 8\r
+  %this1 = load %struct.A*, %struct.A** %this.addr, align 8\r
+  store %struct.A* %this1, %struct.A** %retval, align 8\r
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C@_0N@LJHFFAKD@?5in?5A?5ctor?5?6?$AA@", i64 0, i64 0))\r
+  %0 = load i32, i32* @"?g@@3HA", align 4\r
+  %cmp = icmp eq i32 %0, 0\r
+  br i1 %cmp, label %if.then, label %if.end\r
+\r
+if.then:                                          ; preds = %entry\r
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4\r
+  br label %if.end\r
+\r
+if.end:                                           ; preds = %if.then, %entry\r
+  %1 = load %struct.A*, %struct.A** %retval, align 8\r
+  ret %struct.A* %1\r
+}\r
+\r
+; Function Attrs: nounwind readnone\r
+declare dso_local void @llvm.seh.scope.begin() #3\r
+\r
+; Function Attrs: nounwind readnone\r
+declare dso_local void @llvm.seh.scope.end() #3\r
+\r
+; Function Attrs: noinline nounwind optnone\r
+define internal void @"??1A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* %this) unnamed_addr #0 align 2 {\r
+entry:\r
+  %this.addr = alloca %struct.A*, align 8\r
+  store %struct.A* %this, %struct.A** %this.addr, align 8\r
+  %this1 = load %struct.A*, %struct.A** %this.addr, align 8\r
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@", i64 0, i64 0))\r
+  ret void\r
+}\r
+\r
+declare dso_local void @"?printf@@YAXZZ"(...) #4\r
+\r
+declare dso_local void @_CxxThrowException(i8*, %eh.ThrowInfo*)\r
+\r
+; Function Attrs: noinline norecurse optnone\r
+define dso_local i32 @main() #5 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) {\r
+entry:\r
+  %retval = alloca i32, align 4\r
+  %i = alloca i32, align 4\r
+  %__exception_code = alloca i32, align 4\r
+  store i32 0, i32* %retval, align 4\r
+  store i32 0, i32* %i, align 4\r
+  br label %for.cond\r
+\r
+for.cond:                                         ; preds = %for.inc, %entry\r
+  %0 = load i32, i32* %i, align 4\r
+  %cmp = icmp slt i32 %0, 2\r
+  br i1 %cmp, label %for.body, label %for.end\r
+\r
+for.body:                                         ; preds = %for.cond\r
+  invoke void @llvm.seh.try.begin()\r
+          to label %invoke.cont unwind label %catch.dispatch\r
+\r
+invoke.cont:                                      ; preds = %for.body\r
+  %1 = load volatile i32, i32* %i, align 4\r
+  invoke void @"?crash@@YAXH@Z"(i32 %1) #8\r
+          to label %invoke.cont1 unwind label %catch.dispatch\r
+\r
+invoke.cont1:                                     ; preds = %invoke.cont\r
+  invoke void @llvm.seh.try.end()\r
+          to label %invoke.cont2 unwind label %catch.dispatch\r
+\r
+catch.dispatch:                                   ; preds = %invoke.cont1, %invoke.cont, %for.body\r
+  %2 = catchswitch within none [label %__except] unwind to caller\r
+\r
+__except:                                         ; preds = %catch.dispatch\r
+  %3 = catchpad within %2 [i8* null]\r
+  catchret from %3 to label %__except3\r
+\r
+__except3:                                        ; preds = %__except\r
+  %4 = call i32 @llvm.eh.exceptioncode(token %3)\r
+  store i32 %4, i32* %__exception_code, align 4\r
+  %5 = load i32, i32* %i, align 4\r
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([45 x i8], [45 x i8]* @"??_C@_0CN@MKCAOFNA@?5Test?5CPP?5unwind?3?5in?5except?5hand@", i64 0, i64 0), i32 %5)\r
+  br label %__try.cont\r
+\r
+__try.cont:                                       ; preds = %__except3, %invoke.cont2\r
+  br label %for.inc\r
+\r
+for.inc:                                          ; preds = %__try.cont\r
+  %6 = load i32, i32* %i, align 4\r
+  %inc = add nsw i32 %6, 1\r
+  store i32 %inc, i32* %i, align 4\r
+  br label %for.cond\r
+\r
+invoke.cont2:                                     ; preds = %invoke.cont1\r
+  br label %__try.cont\r
+\r
+for.end:                                          ; preds = %for.cond\r
+  ret i32 0\r
+}\r
+\r
+declare dso_local i32 @__C_specific_handler(...)\r
+\r
+; Function Attrs: nounwind willreturn\r
+declare dso_local void @llvm.seh.try.end() #2\r
+\r
+; Function Attrs: nounwind readnone\r
+declare i32 @llvm.eh.exceptioncode(token) #3\r
+\r
+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" }\r
+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" }\r
+attributes #2 = { nounwind willreturn }\r
+attributes #3 = { nounwind readnone }\r
+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" }\r
+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" }\r
+attributes #6 = { nounwind }\r
+attributes #7 = { noreturn }\r
+attributes #8 = { noinline }\r
+\r
+!llvm.module.flags = !{!0, !1}\r
+\r
+!0 = !{i32 1, !"wchar_size", i32 2}\r
+!1 = !{i32 2, !"eh-asynch", i32 1}\r
+\r
+\r
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 (file)
index 0000000..89528d0
--- /dev/null
@@ -0,0 +1,543 @@
+; RUN: llc -verify-machineinstrs < %s | FileCheck %s
+
+; CHECK-LABEL: $ip2state$main:
+; CHECK-NEXT:  .long   .Lfunc_begin4@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@XZ" = comdat any
+
+$"??1B2@@QEAA@XZ" = comdat any
+
+$"??0B2@@QEAA@XZ" = comdat any
+
+$"??0B3@@QEAA@XZ" = comdat any
+
+$"??1B3@@QEAA@XZ" = comdat any
+
+$"??0B1@@QEAA@XZ" = comdat any
+
+$"??_C@_0N@FMGAAAAM@in?5B1?5Dtor?5?6?$AA@" = comdat any
+
+$"??_C@_0N@GFONDMMJ@in?5B2?5Dtor?5?6?$AA@" = comdat any
+
+$"??_C@_0N@HCJGCIIK@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@_0N@FMGAAAAM@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@_0N@GFONDMMJ@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@_0N@HCJGCIIK@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@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@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@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@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@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@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@_0N@FMGAAAAM@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@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@_0N@GFONDMMJ@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@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@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@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@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@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@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@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@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@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@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@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@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@Z"(i32 99)
+  %add = add nsw i32 %2, %call4
+  br label %cond.end
+
+cond.false:                                       ; preds = %invoke.cont
+  %call7 = invoke %class.B3* @"??0B3@@QEAA@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@_0N@HCJGCIIK@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@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@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@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@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 (file)
index 0000000..8981ceb
--- /dev/null
@@ -0,0 +1,255 @@
+; RUN: llc -verify-machineinstrs < %s | FileCheck %s\r
+\r
+; CHECK-LABEL: "$cppxdata$?crash@@YAXH@Z":\r
+; CHECK:       .long   ("$stateUnwindMap$?crash@@YAXH@Z")\r
+; CHECK:       .long   ("$ip2state$?crash@@YAXH@Z")\r
+\r
+; CHECK-LABEL: "$stateUnwindMap$?crash@@YAXH@Z":\r
+; CHECK:       .long   -1 \r
+; CHECK:       .long   "?dtor$\r
+; CHECK:       .long   0 \r
+; CHECK:       .long   "?dtor$\r
+; CHECK:       .long   1\r
+; CHECK:       .long   "?dtor$\r
+\r
+; CHECK-LABEL: "$ip2state$?crash@@YAXH@Z":\r
+; CHECK-NEXT:  .long   .Lfunc_begin0@IMGREL\r
+; CHECK-NEXT:  .long   -1                  \r
+; CHECK-NEXT:  .long   .Ltmp     \r
+; CHECK-NEXT:  .long   0                   \r
+; CHECK-NEXT:  .long   .Ltmp     \r
+; CHECK-NEXT:  .long   1                   \r
+; CHECK-NEXT:  .long   .Ltmp\r
+; CHECK-NEXT:  .long   2                   \r
+; CHECK-NEXT:  .long   .Ltmp\r
+; CHECK-NEXT:  .long   1                   \r
+; CHECK-NEXT:  .long   .Ltmp\r
+; CHECK-NEXT:  .long   0                   \r
+; CHECK-NEXT:  .long   .Ltmp\r
+; CHECK-NEXT:  .long   -1                  \r
+\r
+; ModuleID = 'windows-seh-EHa-CppDtors01.cpp'\r
+source_filename = "windows-seh-EHa-CppDtors01.cpp"\r
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"\r
+target triple = "x86_64-unknown-windows-msvc"\r
+\r
+%struct.A = type { i8 }\r
+%struct.B = type { i8 }\r
+%struct.C = type { i8 }\r
+\r
+$"??_C@_0CM@KAOHJHDK@?5Test?5CPP?5unwind?3?5in?5catch?5handl@" = comdat any\r
+\r
+$"??_C@_0N@FCCEEGKL@?5in?5C?5dtor?5?6?$AA@" = comdat any\r
+\r
+$"??_C@_0N@EFFPFCOI@?5in?5B?5dtor?5?6?$AA@" = comdat any\r
+\r
+$"??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@" = comdat any\r
+\r
+@"?g@@3HA" = dso_local global i32 0, align 4\r
+@"??_C@_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\r
+@"??_C@_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\r
+@"??_C@_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\r
+@"??_C@_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\r
+\r
+; Function Attrs: noinline optnone\r
+define dso_local void @"?crash@@YAXH@Z"(i32 %i) #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {\r
+entry:\r
+  %i.addr = alloca i32, align 4\r
+  %ObjA = alloca %struct.A, align 1\r
+  %ObjB = alloca %struct.B, align 1\r
+  %ObjC = alloca %struct.C, align 1\r
+  store i32 %i, i32* %i.addr, align 4\r
+  invoke void @llvm.seh.scope.begin()\r
+          to label %invoke.cont unwind label %ehcleanup13\r
+\r
+invoke.cont:                                      ; preds = %entry\r
+  %0 = load i32, i32* %i.addr, align 4\r
+  %cmp = icmp eq i32 %0, 0\r
+  br i1 %cmp, label %if.then, label %if.end\r
+\r
+if.then:                                          ; preds = %invoke.cont\r
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4\r
+  br label %if.end\r
+\r
+if.end:                                           ; preds = %if.then, %invoke.cont\r
+  invoke void @llvm.seh.scope.begin()\r
+          to label %invoke.cont1 unwind label %ehcleanup11\r
+\r
+invoke.cont1:                                     ; preds = %if.end\r
+  %1 = load i32, i32* %i.addr, align 4\r
+  %cmp2 = icmp eq i32 %1, 1\r
+  br i1 %cmp2, label %if.then3, label %if.end4\r
+\r
+if.then3:                                         ; preds = %invoke.cont1\r
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4\r
+  br label %if.end4\r
+\r
+if.end4:                                          ; preds = %if.then3, %invoke.cont1\r
+  invoke void @llvm.seh.scope.begin()\r
+          to label %invoke.cont5 unwind label %ehcleanup\r
+\r
+invoke.cont5:                                     ; preds = %if.end4\r
+  %2 = load i32, i32* %i.addr, align 4\r
+  %cmp6 = icmp eq i32 %2, 2\r
+  br i1 %cmp6, label %if.then7, label %if.end8\r
+\r
+if.then7:                                         ; preds = %invoke.cont5\r
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4\r
+  br label %if.end8\r
+\r
+if.end8:                                          ; preds = %if.then7, %invoke.cont5\r
+  invoke void @llvm.seh.scope.end()\r
+          to label %invoke.cont9 unwind label %ehcleanup\r
+\r
+invoke.cont9:                                     ; preds = %if.end8\r
+  call void @"??1C@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.C* %ObjC) #6\r
+  invoke void @llvm.seh.scope.end()\r
+          to label %invoke.cont10 unwind label %ehcleanup11\r
+\r
+invoke.cont10:                                    ; preds = %invoke.cont9\r
+  call void @"??1B@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.B* %ObjB) #6\r
+  invoke void @llvm.seh.scope.end()\r
+          to label %invoke.cont12 unwind label %ehcleanup13\r
+\r
+invoke.cont12:                                    ; preds = %invoke.cont10\r
+  call void @"??1A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* %ObjA) #6\r
+  ret void\r
+\r
+ehcleanup:                                        ; preds = %if.end8, %if.end4\r
+  %3 = cleanuppad within none []\r
+  call void @"??1C@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.C* %ObjC) #6 [ "funclet"(token %3) ]\r
+  cleanupret from %3 unwind label %ehcleanup11\r
+\r
+ehcleanup11:                                      ; preds = %invoke.cont9, %ehcleanup, %if.end\r
+  %4 = cleanuppad within none []\r
+  call void @"??1B@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.B* %ObjB) #6 [ "funclet"(token %4) ]\r
+  cleanupret from %4 unwind label %ehcleanup13\r
+\r
+ehcleanup13:                                      ; preds = %invoke.cont10, %ehcleanup11, %entry\r
+  %5 = cleanuppad within none []\r
+  call void @"??1A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* %ObjA) #6 [ "funclet"(token %5) ]\r
+  cleanupret from %5 unwind to caller\r
+}\r
+\r
+; Function Attrs: nounwind readnone\r
+declare dso_local void @llvm.seh.scope.begin() #1\r
+\r
+declare dso_local i32 @__CxxFrameHandler3(...)\r
+\r
+; Function Attrs: nounwind readnone\r
+declare dso_local void @llvm.seh.scope.end() #1\r
+\r
+; Function Attrs: noinline nounwind optnone\r
+define internal void @"??1C@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.C* %this) unnamed_addr #2 align 2 {\r
+entry:\r
+  %this.addr = alloca %struct.C*, align 8\r
+  store %struct.C* %this, %struct.C** %this.addr, align 8\r
+  %this1 = load %struct.C*, %struct.C** %this.addr, align 8\r
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C@_0N@FCCEEGKL@?5in?5C?5dtor?5?6?$AA@", i64 0, i64 0))\r
+  ret void\r
+}\r
+\r
+; Function Attrs: noinline nounwind optnone\r
+define internal void @"??1B@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.B* %this) unnamed_addr #2 align 2 {\r
+entry:\r
+  %this.addr = alloca %struct.B*, align 8\r
+  store %struct.B* %this, %struct.B** %this.addr, align 8\r
+  %this1 = load %struct.B*, %struct.B** %this.addr, align 8\r
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C@_0N@EFFPFCOI@?5in?5B?5dtor?5?6?$AA@", i64 0, i64 0))\r
+  ret void\r
+}\r
+\r
+; Function Attrs: noinline nounwind optnone\r
+define internal void @"??1A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* %this) unnamed_addr #2 align 2 {\r
+entry:\r
+  %this.addr = alloca %struct.A*, align 8\r
+  store %struct.A* %this, %struct.A** %this.addr, align 8\r
+  %this1 = load %struct.A*, %struct.A** %this.addr, align 8\r
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@", i64 0, i64 0))\r
+  ret void\r
+}\r
+\r
+; Function Attrs: noinline norecurse optnone\r
+define dso_local i32 @main() #3 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) {\r
+entry:\r
+  %retval = alloca i32, align 4\r
+  %i = alloca i32, align 4\r
+  %__exception_code = alloca i32, align 4\r
+  store i32 0, i32* %retval, align 4\r
+  store i32 0, i32* %i, align 4\r
+  br label %for.cond\r
+\r
+for.cond:                                         ; preds = %for.inc, %entry\r
+  %0 = load i32, i32* %i, align 4\r
+  %cmp = icmp slt i32 %0, 3\r
+  br i1 %cmp, label %for.body, label %for.end\r
+\r
+for.body:                                         ; preds = %for.cond\r
+  invoke void @llvm.seh.try.begin()\r
+          to label %invoke.cont unwind label %catch.dispatch\r
+\r
+invoke.cont:                                      ; preds = %for.body\r
+  %1 = load volatile i32, i32* %i, align 4\r
+  invoke void @"?crash@@YAXH@Z"(i32 %1) #7\r
+          to label %invoke.cont1 unwind label %catch.dispatch\r
+\r
+invoke.cont1:                                     ; preds = %invoke.cont\r
+  invoke void @llvm.seh.try.end()\r
+          to label %invoke.cont2 unwind label %catch.dispatch\r
+\r
+catch.dispatch:                                   ; preds = %invoke.cont1, %invoke.cont, %for.body\r
+  %2 = catchswitch within none [label %__except] unwind to caller\r
+\r
+__except:                                         ; preds = %catch.dispatch\r
+  %3 = catchpad within %2 [i8* null]\r
+  catchret from %3 to label %__except3\r
+\r
+__except3:                                        ; preds = %__except\r
+  %4 = call i32 @llvm.eh.exceptioncode(token %3)\r
+  store i32 %4, i32* %__exception_code, align 4\r
+  %5 = load i32, i32* %i, align 4\r
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([44 x i8], [44 x i8]* @"??_C@_0CM@KAOHJHDK@?5Test?5CPP?5unwind?3?5in?5catch?5handl@", i64 0, i64 0), i32 %5)\r
+  br label %__try.cont\r
+\r
+__try.cont:                                       ; preds = %__except3, %invoke.cont2\r
+  br label %for.inc\r
+\r
+for.inc:                                          ; preds = %__try.cont\r
+  %6 = load i32, i32* %i, align 4\r
+  %inc = add nsw i32 %6, 1\r
+  store i32 %inc, i32* %i, align 4\r
+  br label %for.cond\r
+\r
+invoke.cont2:                                     ; preds = %invoke.cont1\r
+  br label %__try.cont\r
+\r
+for.end:                                          ; preds = %for.cond\r
+  ret i32 0\r
+}\r
+\r
+; Function Attrs: nounwind willreturn\r
+declare dso_local void @llvm.seh.try.begin() #4\r
+\r
+declare dso_local i32 @__C_specific_handler(...)\r
+\r
+; Function Attrs: nounwind willreturn\r
+declare dso_local void @llvm.seh.try.end() #4\r
+\r
+; Function Attrs: nounwind readnone\r
+declare i32 @llvm.eh.exceptioncode(token) #1\r
+\r
+declare dso_local void @"?printf@@YAXZZ"(...) #5\r
+\r
+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" }\r
+attributes #1 = { nounwind readnone }\r
+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" }\r
+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" }\r
+attributes #4 = { nounwind willreturn }\r
+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" }\r
+attributes #6 = { nounwind }\r
+attributes #7 = { noinline }\r
+\r
+!llvm.module.flags = !{!0, !1}\r
+\r
+!0 = !{i32 1, !"wchar_size", i32 2}\r
+!1 = !{i32 2, !"eh-asynch", i32 1}\r
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 (file)
index 0000000..4fed375
--- /dev/null
@@ -0,0 +1,224 @@
+; RUN: llc -verify-machineinstrs < %s | FileCheck %s\r
+\r
+; CHECK-LABEL: "?fin$0@0@main@@"\r
+; CHECK:      .seh_handlerdata\r
+; CHECK:      .set ".L?fin$0@0@main@@$parent_frame_offset", 48\r
+; CHECK-NEXT:        .long   (.Llsda_end1-.Llsda_begin1)/16 \r
+; CHECK-NEXT: .Llsda_begin1:\r
+; CHECK-NEXT:        .long   .Ltmp\r
+; CHECK-NEXT:        .long   .Ltmp\r
+; CHECK-NEXT:        .long   "?dtor$\r
+; CHECK-NEXT:        .long   0\r
+; CHECK-NEXT: .Llsda_end1:\r
+\r
+; ModuleID = 'windows-seh-EHa-TryInFinally.cpp'\r
+source_filename = "windows-seh-EHa-TryInFinally.cpp"\r
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"\r
+target triple = "x86_64-unknown-windows-msvc"\r
+\r
+$"??_C@_0CI@MDFPIOJJ@?5?9?9?9?5Test?5_Try?5in?5_finally?5?9?9?9?5i@" = comdat any\r
+\r
+$"??_C@_0BN@HHKJHLBE@?5?5In?5Inner?5_finally?5i?5?$DN?5?$CFd?5?6?$AA@" = comdat any\r
+\r
+$"??_C@_0BN@HAIIIOKI@?5?5In?5outer?5_finally?5i?5?$DN?5?$CFd?5?6?$AA@" = comdat any\r
+\r
+$"??_C@_0BJ@OJMMAGCD@?5?5In?5outer?5_try?5i?5?$DN?5?$CFd?5?6?$AA@" = comdat any\r
+\r
+$"??_C@_0CG@ENDJHCGA@?5?9?9?9?5In?5outer?5except?5handler?5i?5?$DN@" = comdat any\r
+\r
+@"??_C@_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\r
+@"??_C@_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\r
+@"??_C@_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\r
+@"??_C@_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\r
+@"??_C@_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\r
+\r
+; Function Attrs: noinline norecurse optnone\r
+define dso_local i32 @main() #0 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) {\r
+entry:\r
+  %retval = alloca i32, align 4\r
+  %i = alloca i32, align 4\r
+  %__exception_code = alloca i32, align 4\r
+  call void (...) @llvm.localescape(i32* %i)\r
+  store i32 0, i32* %retval, align 4\r
+  store i32 0, i32* %i, align 4\r
+  br label %for.cond\r
+\r
+for.cond:                                         ; preds = %for.inc, %entry\r
+  %0 = load i32, i32* %i, align 4\r
+  %cmp = icmp slt i32 %0, 3\r
+  br i1 %cmp, label %for.body, label %for.end\r
+\r
+for.body:                                         ; preds = %for.cond\r
+  %1 = load i32, i32* %i, align 4\r
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([40 x i8], [40 x i8]* @"??_C@_0CI@MDFPIOJJ@?5?9?9?9?5Test?5_Try?5in?5_finally?5?9?9?9?5i@", i64 0, i64 0), i32 %1)\r
+  invoke void @llvm.seh.try.begin()\r
+          to label %invoke.cont unwind label %catch.dispatch\r
+\r
+invoke.cont:                                      ; preds = %for.body\r
+  invoke void @llvm.seh.try.begin()\r
+          to label %invoke.cont1 unwind label %ehcleanup\r
+\r
+invoke.cont1:                                     ; preds = %invoke.cont\r
+  %2 = load volatile i32, i32* %i, align 4\r
+  invoke void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @"??_C@_0BJ@OJMMAGCD@?5?5In?5outer?5_try?5i?5?$DN?5?$CFd?5?6?$AA@", i64 0, i64 0), i32 %2) #6\r
+          to label %invoke.cont2 unwind label %ehcleanup\r
+\r
+invoke.cont2:                                     ; preds = %invoke.cont1\r
+  %3 = load volatile i32, i32* %i, align 4\r
+  %cmp3 = icmp eq i32 %3, 0\r
+  br i1 %cmp3, label %if.then, label %if.end\r
+\r
+if.then:                                          ; preds = %invoke.cont2\r
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4\r
+  br label %if.end\r
+\r
+if.end:                                           ; preds = %if.then, %invoke.cont2\r
+  invoke void @llvm.seh.try.end()\r
+          to label %invoke.cont4 unwind label %ehcleanup\r
+\r
+invoke.cont4:                                     ; preds = %if.end\r
+  %4 = call i8* @llvm.localaddress()\r
+  invoke void @"?fin$0@0@main@@"(i8 0, i8* %4) #6\r
+          to label %invoke.cont5 unwind label %catch.dispatch\r
+\r
+invoke.cont5:                                     ; preds = %invoke.cont4\r
+  invoke void @llvm.seh.try.end()\r
+          to label %invoke.cont7 unwind label %catch.dispatch\r
+\r
+catch.dispatch:                                   ; preds = %invoke.cont5, %invoke.cont6, %ehcleanup, %invoke.cont4, %for.body\r
+  %5 = catchswitch within none [label %__except] unwind to caller\r
+\r
+__except:                                         ; preds = %catch.dispatch\r
+  %6 = catchpad within %5 [i8* null]\r
+  catchret from %6 to label %__except8\r
+\r
+__except8:                                        ; preds = %__except\r
+  %7 = call i32 @llvm.eh.exceptioncode(token %6)\r
+  store i32 %7, i32* %__exception_code, align 4\r
+  %8 = load i32, i32* %i, align 4\r
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([38 x i8], [38 x i8]* @"??_C@_0CG@ENDJHCGA@?5?9?9?9?5In?5outer?5except?5handler?5i?5?$DN@", i64 0, i64 0), i32 %8)\r
+  br label %__try.cont\r
+\r
+__try.cont:                                       ; preds = %__except8, %invoke.cont7\r
+  br label %for.inc\r
+\r
+for.inc:                                          ; preds = %__try.cont\r
+  %9 = load i32, i32* %i, align 4\r
+  %inc = add nsw i32 %9, 1\r
+  store i32 %inc, i32* %i, align 4\r
+  br label %for.cond\r
+\r
+invoke.cont7:                                     ; preds = %invoke.cont5\r
+  br label %__try.cont\r
+\r
+ehcleanup:                                        ; preds = %if.end, %invoke.cont1, %invoke.cont\r
+  %10 = cleanuppad within none []\r
+  %11 = call i8* @llvm.localaddress()\r
+  invoke void @"?fin$0@0@main@@"(i8 1, i8* %11) #6 [ "funclet"(token %10) ]\r
+          to label %invoke.cont6 unwind label %catch.dispatch\r
+\r
+invoke.cont6:                                     ; preds = %ehcleanup\r
+  cleanupret from %10 unwind label %catch.dispatch\r
+\r
+for.end:                                          ; preds = %for.cond\r
+  ret i32 0\r
+}\r
+\r
+declare dso_local void @"?printf@@YAXZZ"(...) #1\r
+\r
+; Function Attrs: nounwind willreturn\r
+declare dso_local void @llvm.seh.try.begin() #2\r
+\r
+declare dso_local i32 @__C_specific_handler(...)\r
+\r
+; Function Attrs: noinline\r
+define internal void @"?fin$0@0@main@@"(i8 %abnormal_termination, i8* %frame_pointer) #3 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) {\r
+entry:\r
+  %frame_pointer.addr = alloca i8*, align 8\r
+  %abnormal_termination.addr = alloca i8, align 1\r
+  %0 = call i8* @llvm.localrecover(i8* bitcast (i32 ()* @main to i8*), i8* %frame_pointer, i32 0)\r
+  %i = bitcast i8* %0 to i32*\r
+  store i8* %frame_pointer, i8** %frame_pointer.addr, align 8\r
+  store i8 %abnormal_termination, i8* %abnormal_termination.addr, align 1\r
+  invoke void @llvm.seh.try.begin()\r
+          to label %invoke.cont unwind label %ehcleanup\r
+\r
+invoke.cont:                                      ; preds = %entry\r
+  %1 = load volatile i32, i32* %i, align 4\r
+  invoke void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([29 x i8], [29 x i8]* @"??_C@_0BN@HAIIIOKI@?5?5In?5outer?5_finally?5i?5?$DN?5?$CFd?5?6?$AA@", i64 0, i64 0), i32 %1) #6\r
+          to label %invoke.cont1 unwind label %ehcleanup\r
+\r
+invoke.cont1:                                     ; preds = %invoke.cont\r
+  %2 = load volatile i32, i32* %i, align 4\r
+  %cmp = icmp eq i32 %2, 1\r
+  br i1 %cmp, label %if.then, label %if.end\r
+\r
+if.then:                                          ; preds = %invoke.cont1\r
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4\r
+  br label %if.end\r
+\r
+if.end:                                           ; preds = %if.then, %invoke.cont1\r
+  invoke void @llvm.seh.try.end()\r
+          to label %invoke.cont2 unwind label %ehcleanup\r
+\r
+invoke.cont2:                                     ; preds = %if.end\r
+  call void @"?fin$1@0@main@@"(i8 0, i8* %frame_pointer)\r
+  ret void\r
+\r
+ehcleanup:                                        ; preds = %if.end, %invoke.cont, %entry\r
+  %3 = cleanuppad within none []\r
+  call void @"?fin$1@0@main@@"(i8 1, i8* %frame_pointer) [ "funclet"(token %3) ]\r
+  cleanupret from %3 unwind to caller\r
+}\r
+\r
+; Function Attrs: nounwind readnone\r
+declare i8* @llvm.localrecover(i8*, i8*, i32 immarg) #4\r
+\r
+; Function Attrs: noinline\r
+define internal void @"?fin$1@0@main@@"(i8 %abnormal_termination, i8* %frame_pointer) #3 {\r
+entry:\r
+  %frame_pointer.addr = alloca i8*, align 8\r
+  %abnormal_termination.addr = alloca i8, align 1\r
+  %0 = call i8* @llvm.localrecover(i8* bitcast (i32 ()* @main to i8*), i8* %frame_pointer, i32 0)\r
+  %i = bitcast i8* %0 to i32*\r
+  store i8* %frame_pointer, i8** %frame_pointer.addr, align 8\r
+  store i8 %abnormal_termination, i8* %abnormal_termination.addr, align 1\r
+  %1 = load i32, i32* %i, align 4\r
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([29 x i8], [29 x i8]* @"??_C@_0BN@HHKJHLBE@?5?5In?5Inner?5_finally?5i?5?$DN?5?$CFd?5?6?$AA@", i64 0, i64 0), i32 %1)\r
+  %2 = load i32, i32* %i, align 4\r
+  %cmp = icmp eq i32 %2, 2\r
+  br i1 %cmp, label %if.then, label %if.end\r
+\r
+if.then:                                          ; preds = %entry\r
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4\r
+  br label %if.end\r
+\r
+if.end:                                           ; preds = %if.then, %entry\r
+  ret void\r
+}\r
+\r
+; Function Attrs: nounwind willreturn\r
+declare dso_local void @llvm.seh.try.end() #2\r
+\r
+; Function Attrs: nounwind readnone\r
+declare i8* @llvm.localaddress() #4\r
+\r
+; Function Attrs: nounwind readnone\r
+declare i32 @llvm.eh.exceptioncode(token) #4\r
+\r
+; Function Attrs: nounwind\r
+declare void @llvm.localescape(...) #5\r
+\r
+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" }\r
+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" }\r
+attributes #2 = { nounwind willreturn }\r
+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" }\r
+attributes #4 = { nounwind readnone }\r
+attributes #5 = { nounwind }\r
+attributes #6 = { noinline }\r
+\r
+!llvm.module.flags = !{!0, !1}\r
+\r
+!0 = !{i32 1, !"wchar_size", i32 2}\r
+!1 = !{i32 2, !"eh-asynch", i32 1}\r
+\r