فهرست منبع

[WinEH] Run cleanup handlers when an exception is thrown

Generate tables in the .xdata section representing what actions to take
when an exception is thrown.  This currently fills in state for
cleanups, catch handlers are still unfinished.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@233636 91177308-0d34-0410-b5e6-96231b3b80d8
David Majnemer 10 سال پیش
والد
کامیت
0a8ff297ad

+ 21 - 8
include/llvm/CodeGen/MachineModuleInfo.h

@@ -58,22 +58,25 @@ class MachineFunction;
 class Module;
 class Module;
 class PointerType;
 class PointerType;
 class StructType;
 class StructType;
+struct WinEHFuncInfo;
 
 
 //===----------------------------------------------------------------------===//
 //===----------------------------------------------------------------------===//
 /// LandingPadInfo - This structure is used to retain landing pad info for
 /// LandingPadInfo - This structure is used to retain landing pad info for
 /// the current function.
 /// the current function.
 ///
 ///
 struct LandingPadInfo {
 struct LandingPadInfo {
-  MachineBasicBlock *LandingPadBlock;    // Landing pad block.
-  SmallVector<MCSymbol*, 1> BeginLabels; // Labels prior to invoke.
-  SmallVector<MCSymbol*, 1> EndLabels;   // Labels after invoke.
-  SmallVector<MCSymbol*, 1> ClauseLabels; // Labels for each clause.
-  MCSymbol *LandingPadLabel;             // Label at beginning of landing pad.
-  const Function *Personality;           // Personality function.
-  std::vector<int> TypeIds;              // List of type ids (filters negative)
+  MachineBasicBlock *LandingPadBlock;      // Landing pad block.
+  SmallVector<MCSymbol *, 1> BeginLabels;  // Labels prior to invoke.
+  SmallVector<MCSymbol *, 1> EndLabels;    // Labels after invoke.
+  SmallVector<MCSymbol *, 1> ClauseLabels; // Labels for each clause.
+  MCSymbol *LandingPadLabel;               // Label at beginning of landing pad.
+  const Function *Personality;             // Personality function.
+  std::vector<int> TypeIds;               // List of type ids (filters negative).
+  int WinEHState;                         // WinEH specific state number.
 
 
   explicit LandingPadInfo(MachineBasicBlock *MBB)
   explicit LandingPadInfo(MachineBasicBlock *MBB)
-    : LandingPadBlock(MBB), LandingPadLabel(nullptr), Personality(nullptr) {}
+      : LandingPadBlock(MBB), LandingPadLabel(nullptr), Personality(nullptr),
+        WinEHState(-1) {}
 };
 };
 
 
 //===----------------------------------------------------------------------===//
 //===----------------------------------------------------------------------===//
@@ -172,6 +175,8 @@ class MachineModuleInfo : public ImmutablePass {
 
 
   EHPersonality PersonalityTypeCache;
   EHPersonality PersonalityTypeCache;
 
 
+  DenseMap<const Function *, std::unique_ptr<WinEHFuncInfo>> FuncInfoMap;
+
 public:
 public:
   static char ID; // Pass identification, replacement for typeid
   static char ID; // Pass identification, replacement for typeid
 
 
@@ -207,6 +212,12 @@ public:
   void setModule(const Module *M) { TheModule = M; }
   void setModule(const Module *M) { TheModule = M; }
   const Module *getModule() const { return TheModule; }
   const Module *getModule() const { return TheModule; }
 
 
+  const Function *getWinEHParent(const Function *F) const;
+  WinEHFuncInfo &getWinEHFuncInfo(const Function *F);
+  bool hasWinEHFuncInfo(const Function *F) const {
+    return FuncInfoMap.count(getWinEHParent(F)) > 0;
+  }
+
   /// getInfo - Keep track of various per-function pieces of information for
   /// getInfo - Keep track of various per-function pieces of information for
   /// backends that would like to do so.
   /// backends that would like to do so.
   ///
   ///
@@ -304,6 +315,8 @@ public:
   void addPersonality(MachineBasicBlock *LandingPad,
   void addPersonality(MachineBasicBlock *LandingPad,
                       const Function *Personality);
                       const Function *Personality);
 
 
+  void addWinEHState(MachineBasicBlock *LandingPad, int State);
+
   /// getPersonalityIndex - Get index of the current personality function inside
   /// getPersonalityIndex - Get index of the current personality function inside
   /// Personalitites array
   /// Personalitites array
   unsigned getPersonalityIndex() const;
   unsigned getPersonalityIndex() const;

+ 131 - 0
include/llvm/CodeGen/WinEHFuncInfo.h

@@ -0,0 +1,131 @@
+//===-- llvm/CodeGen/WinEHFuncInfo.h ----------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Data structures and associated state for Windows exception handling schemes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_WINEHFUNCINFO_H
+#define LLVM_CODEGEN_WINEHFUNCINFO_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/TinyPtrVector.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace llvm {
+class BasicBlock;
+class Constant;
+class Function;
+class GlobalValue;
+class LandingPadInst;
+class MCSymbol;
+class Value;
+
+enum ActionType { Catch, Cleanup };
+
+class ActionHandler {
+public:
+  ActionHandler(BasicBlock *BB, ActionType Type)
+      : StartBB(BB), Type(Type), EHState(-1), HandlerBlockOrFunc(nullptr) {}
+
+  ActionType getType() const { return Type; }
+  BasicBlock *getStartBlock() const { return StartBB; }
+
+  bool hasBeenProcessed() { return HandlerBlockOrFunc != nullptr; }
+
+  void setHandlerBlockOrFunc(Constant *F) { HandlerBlockOrFunc = F; }
+  Constant *getHandlerBlockOrFunc() { return HandlerBlockOrFunc; }
+
+  void setEHState(int State) { EHState = State; }
+  int getEHState() const { return EHState; }
+
+private:
+  BasicBlock *StartBB;
+  ActionType Type;
+  int EHState;
+
+  // Can be either a BlockAddress or a Function depending on the EH personality.
+  Constant *HandlerBlockOrFunc;
+};
+
+class CatchHandler : public ActionHandler {
+public:
+  CatchHandler(BasicBlock *BB, Constant *Selector, BasicBlock *NextBB)
+      : ActionHandler(BB, ActionType::Catch), Selector(Selector),
+        NextBB(NextBB), ExceptionObjectVar(nullptr) {}
+
+  // Method for support type inquiry through isa, cast, and dyn_cast:
+  static inline bool classof(const ActionHandler *H) {
+    return H->getType() == ActionType::Catch;
+  }
+
+  Constant *getSelector() const { return Selector; }
+  BasicBlock *getNextBB() const { return NextBB; }
+
+  const Value *getExceptionVar() { return ExceptionObjectVar; }
+  TinyPtrVector<BasicBlock *> &getReturnTargets() { return ReturnTargets; }
+
+  void setExceptionVar(const Value *Val) { ExceptionObjectVar = Val; }
+  void setReturnTargets(TinyPtrVector<BasicBlock *> &Targets) {
+    ReturnTargets = Targets;
+  }
+
+private:
+  Constant *Selector;
+  BasicBlock *NextBB;
+  const Value *ExceptionObjectVar;
+  TinyPtrVector<BasicBlock *> ReturnTargets;
+};
+
+class CleanupHandler : public ActionHandler {
+public:
+  CleanupHandler(BasicBlock *BB) : ActionHandler(BB, ActionType::Cleanup) {}
+
+  // Method for support type inquiry through isa, cast, and dyn_cast:
+  static inline bool classof(const ActionHandler *H) {
+    return H->getType() == ActionType::Cleanup;
+  }
+};
+
+// The following structs respresent the .xdata for functions using C++
+// exceptions on Windows.
+
+struct WinEHUnwindMapEntry {
+  int ToState;
+  Function *Cleanup;
+};
+
+struct WinEHHandlerType {
+  int Adjectives;
+  GlobalValue *TypeDescriptor;
+  Function *Handler;
+};
+
+struct WinEHTryBlockMapEntry {
+  int TryLow;
+  int TryHigh;
+  int CatchHigh;
+  SmallVector<WinEHHandlerType, 4> HandlerArray;
+};
+
+struct WinEHFuncInfo {
+  DenseMap<const LandingPadInst *, int> LandingPadStateMap;
+  DenseMap<const Function *, int> CatchHandlerParentFrameObjIdx;
+  DenseMap<const Function *, int> CatchHandlerParentFrameObjOffset;
+  SmallVector<WinEHUnwindMapEntry, 4> UnwindMap;
+  SmallVector<WinEHTryBlockMapEntry, 4> TryBlockMap;
+  SmallVector<std::pair<MCSymbol *, int>, 4> IPToStateList;
+  int UnwindHelpFrameIdx;
+  int UnwindHelpFrameOffset;
+
+  WinEHFuncInfo() : UnwindHelpFrameIdx(INT_MAX), UnwindHelpFrameOffset(-1) {}
+};
+
+}
+#endif // LLVM_CODEGEN_WINEHFUNCINFO_H

+ 1 - 0
include/llvm/IR/CallSite.h

@@ -373,6 +373,7 @@ private:
 class ImmutableCallSite : public CallSiteBase<> {
 class ImmutableCallSite : public CallSiteBase<> {
   typedef CallSiteBase<> Base;
   typedef CallSiteBase<> Base;
 public:
 public:
+  ImmutableCallSite() {}
   ImmutableCallSite(const Value* V) : Base(V) {}
   ImmutableCallSite(const Value* V) : Base(V) {}
   ImmutableCallSite(const CallInst *CI) : Base(CI) {}
   ImmutableCallSite(const CallInst *CI) : Base(CI) {}
   ImmutableCallSite(const InvokeInst *II) : Base(II) {}
   ImmutableCallSite(const InvokeInst *II) : Base(II) {}

+ 1 - 3
lib/Analysis/TargetLibraryInfo.cpp

@@ -409,9 +409,7 @@ static StringRef sanitizeFunctionName(StringRef funcName) {
 
 
   // Check for \01 prefix that is used to mangle __asm declarations and
   // Check for \01 prefix that is used to mangle __asm declarations and
   // strip it if present.
   // strip it if present.
-  if (funcName.front() == '\01')
-    funcName = funcName.substr(1);
-  return funcName;
+  return GlobalValue::getRealLinkageName(funcName);
 }
 }
 
 
 bool TargetLibraryInfoImpl::getLibFunc(StringRef funcName,
 bool TargetLibraryInfoImpl::getLibFunc(StringRef funcName,

+ 17 - 11
lib/CodeGen/AsmPrinter/EHStreamer.cpp

@@ -188,20 +188,12 @@ bool EHStreamer::callToNoUnwindFunction(const MachineInstr *MI) {
   return MarkedNoUnwind;
   return MarkedNoUnwind;
 }
 }
 
 
-/// Compute the call-site table.  The entry for an invoke has a try-range
-/// containing the call, a non-zero landing pad, and an appropriate action.  The
-/// entry for an ordinary call has a try-range containing the call and zero for
-/// the landing pad and the action.  Calls marked 'nounwind' have no entry and
-/// must not be contained in the try-range of any entry - they form gaps in the
-/// table.  Entries must be ordered by try-range address.
-void EHStreamer::
-computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites,
-                     const SmallVectorImpl<const LandingPadInfo *> &LandingPads,
-                     const SmallVectorImpl<unsigned> &FirstActions) {
+void EHStreamer::computePadMap(
+    const SmallVectorImpl<const LandingPadInfo *> &LandingPads,
+    RangeMapType &PadMap) {
   // Invokes and nounwind calls have entries in PadMap (due to being bracketed
   // Invokes and nounwind calls have entries in PadMap (due to being bracketed
   // by try-range labels when lowered).  Ordinary calls do not, so appropriate
   // by try-range labels when lowered).  Ordinary calls do not, so appropriate
   // try-ranges for them need be deduced so we can put them in the LSDA.
   // try-ranges for them need be deduced so we can put them in the LSDA.
-  RangeMapType PadMap;
   for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) {
   for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) {
     const LandingPadInfo *LandingPad = LandingPads[i];
     const LandingPadInfo *LandingPad = LandingPads[i];
     for (unsigned j = 0, E = LandingPad->BeginLabels.size(); j != E; ++j) {
     for (unsigned j = 0, E = LandingPad->BeginLabels.size(); j != E; ++j) {
@@ -211,6 +203,20 @@ computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites,
       PadMap[BeginLabel] = P;
       PadMap[BeginLabel] = P;
     }
     }
   }
   }
+}
+
+/// Compute the call-site table.  The entry for an invoke has a try-range
+/// containing the call, a non-zero landing pad, and an appropriate action.  The
+/// entry for an ordinary call has a try-range containing the call and zero for
+/// the landing pad and the action.  Calls marked 'nounwind' have no entry and
+/// must not be contained in the try-range of any entry - they form gaps in the
+/// table.  Entries must be ordered by try-range address.
+void EHStreamer::
+computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites,
+                     const SmallVectorImpl<const LandingPadInfo *> &LandingPads,
+                     const SmallVectorImpl<unsigned> &FirstActions) {
+  RangeMapType PadMap;
+  computePadMap(LandingPads, PadMap);
 
 
   // The end label of the previous invoke or nounwind try-range.
   // The end label of the previous invoke or nounwind try-range.
   MCSymbol *LastLabel = nullptr;
   MCSymbol *LastLabel = nullptr;

+ 3 - 1
lib/CodeGen/AsmPrinter/EHStreamer.h

@@ -80,13 +80,15 @@ protected:
   /// `false' otherwise.
   /// `false' otherwise.
   bool callToNoUnwindFunction(const MachineInstr *MI);
   bool callToNoUnwindFunction(const MachineInstr *MI);
 
 
+  void computePadMap(const SmallVectorImpl<const LandingPadInfo *> &LandingPads,
+                     RangeMapType &PadMap);
+
   /// Compute the call-site table.  The entry for an invoke has a try-range
   /// Compute the call-site table.  The entry for an invoke has a try-range
   /// containing the call, a non-zero landing pad and an appropriate action.
   /// containing the call, a non-zero landing pad and an appropriate action.
   /// The entry for an ordinary call has a try-range containing the call and
   /// The entry for an ordinary call has a try-range containing the call and
   /// zero for the landing pad and the action.  Calls marked 'nounwind' have
   /// zero for the landing pad and the action.  Calls marked 'nounwind' have
   /// no entry and must not be contained in the try-range of any entry - they
   /// no entry and must not be contained in the try-range of any entry - they
   /// form gaps in the table.  Entries must be ordered by try-range address.
   /// form gaps in the table.  Entries must be ordered by try-range address.
-
   void computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites,
   void computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites,
                             const SmallVectorImpl<const LandingPadInfo *> &LPs,
                             const SmallVectorImpl<const LandingPadInfo *> &LPs,
                             const SmallVectorImpl<unsigned> &FirstActions);
                             const SmallVectorImpl<unsigned> &FirstActions);

+ 210 - 2
lib/CodeGen/AsmPrinter/Win64Exception.cpp

@@ -19,6 +19,7 @@
 #include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineModuleInfo.h"
 #include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/WinEHFuncInfo.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/Mangler.h"
 #include "llvm/IR/Mangler.h"
 #include "llvm/IR/Module.h"
 #include "llvm/IR/Module.h"
@@ -82,7 +83,7 @@ void Win64Exception::beginFunction(const MachineFunction *MF) {
 
 
 /// endFunction - Gather and emit post-function exception information.
 /// endFunction - Gather and emit post-function exception information.
 ///
 ///
-void Win64Exception::endFunction(const MachineFunction *) {
+void Win64Exception::endFunction(const MachineFunction *MF) {
   if (!shouldEmitPersonality && !shouldEmitMoves)
   if (!shouldEmitPersonality && !shouldEmitMoves)
     return;
     return;
 
 
@@ -100,6 +101,8 @@ void Win64Exception::endFunction(const MachineFunction *) {
     EHPersonality Per = MMI->getPersonalityType();
     EHPersonality Per = MMI->getPersonalityType();
     if (Per == EHPersonality::MSVC_Win64SEH)
     if (Per == EHPersonality::MSVC_Win64SEH)
       emitCSpecificHandlerTable();
       emitCSpecificHandlerTable();
+    else if (Per == EHPersonality::MSVC_CXX)
+      emitCXXFrameHandler3Table(MF);
     else
     else
       emitExceptionTable();
       emitExceptionTable();
 
 
@@ -108,11 +111,19 @@ void Win64Exception::endFunction(const MachineFunction *) {
   Asm->OutStreamer.EmitWinCFIEndProc();
   Asm->OutStreamer.EmitWinCFIEndProc();
 }
 }
 
 
-const MCSymbolRefExpr *Win64Exception::createImageRel32(const MCSymbol *Value) {
+const MCExpr *Win64Exception::createImageRel32(const MCSymbol *Value) {
+  if (!Value)
+    return MCConstantExpr::Create(0, Asm->OutContext);
   return MCSymbolRefExpr::Create(Value, MCSymbolRefExpr::VK_COFF_IMGREL32,
   return MCSymbolRefExpr::Create(Value, MCSymbolRefExpr::VK_COFF_IMGREL32,
                                  Asm->OutContext);
                                  Asm->OutContext);
 }
 }
 
 
+const MCExpr *Win64Exception::createImageRel32(const GlobalValue *GV) {
+  if (!GV)
+    return MCConstantExpr::Create(0, Asm->OutContext);
+  return createImageRel32(Asm->getSymbol(GV));
+}
+
 /// Emit the language-specific data that __C_specific_handler expects.  This
 /// Emit the language-specific data that __C_specific_handler expects.  This
 /// handler lives in the x64 Microsoft C runtime and allows catching or cleaning
 /// handler lives in the x64 Microsoft C runtime and allows catching or cleaning
 /// up after faults with __try, __except, and __finally.  The typeinfo values
 /// up after faults with __try, __except, and __finally.  The typeinfo values
@@ -237,3 +248,200 @@ void Win64Exception::emitCSpecificHandlerTable() {
     }
     }
   }
   }
 }
 }
+
+void Win64Exception::emitCXXFrameHandler3Table(const MachineFunction *MF) {
+  const Function *F = MF->getFunction();
+  const Function *ParentF = MMI->getWinEHParent(F);
+  auto &OS = Asm->OutStreamer;
+
+  StringRef ParentLinkageName =
+      GlobalValue::getRealLinkageName(ParentF->getName());
+
+  MCSymbol *FuncInfoXData =
+      Asm->OutContext.GetOrCreateSymbol(Twine("$cppxdata$", ParentLinkageName));
+  OS.EmitValue(createImageRel32(FuncInfoXData), 4);
+
+  // The Itanium LSDA table sorts similar landing pads together to simplify the
+  // actions table, but we don't need that.
+  SmallVector<const LandingPadInfo *, 64> LandingPads;
+  const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
+  LandingPads.reserve(PadInfos.size());
+  for (const auto &LP : PadInfos)
+    LandingPads.push_back(&LP);
+
+  RangeMapType PadMap;
+  computePadMap(LandingPads, PadMap);
+
+  // The end label of the previous invoke or nounwind try-range.
+  MCSymbol *LastLabel = Asm->getFunctionBegin();
+
+  // Whether there is a potentially throwing instruction (currently this means
+  // an ordinary call) between the end of the previous try-range and now.
+  bool SawPotentiallyThrowing = false;
+
+  WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF);
+
+  int LastEHState = -2;
+
+  // The parent function and the catch handlers contribute to the 'ip2state'
+  // table.
+  for (const auto &MBB : *MF) {
+    for (const auto &MI : MBB) {
+      if (!MI.isEHLabel()) {
+        if (MI.isCall())
+          SawPotentiallyThrowing |= !callToNoUnwindFunction(&MI);
+        continue;
+      }
+
+      // End of the previous try-range?
+      MCSymbol *BeginLabel = MI.getOperand(0).getMCSymbol();
+      if (BeginLabel == LastLabel)
+        SawPotentiallyThrowing = false;
+
+      // Beginning of a new try-range?
+      RangeMapType::const_iterator L = PadMap.find(BeginLabel);
+      if (L == PadMap.end())
+        // Nope, it was just some random label.
+        continue;
+
+      const PadRange &P = L->second;
+      const LandingPadInfo *LandingPad = LandingPads[P.PadIndex];
+      assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] &&
+             "Inconsistent landing pad map!");
+
+      if (SawPotentiallyThrowing) {
+        FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1));
+        SawPotentiallyThrowing = false;
+        LastEHState = -1;
+      }
+
+      if (LandingPad->WinEHState != LastEHState)
+        FuncInfo.IPToStateList.push_back(
+            std::make_pair(BeginLabel, LandingPad->WinEHState));
+      LastEHState = LandingPad->WinEHState;
+      LastLabel = LandingPad->EndLabels[P.RangeIndex];
+    }
+  }
+
+  if (ParentF != F)
+    return;
+
+  MCSymbol *UnwindMapXData = nullptr;
+  MCSymbol *TryBlockMapXData = nullptr;
+  MCSymbol *IPToStateXData = nullptr;
+  if (!FuncInfo.UnwindMap.empty())
+    UnwindMapXData = Asm->OutContext.GetOrCreateSymbol(
+        Twine("$stateUnwindMap$", ParentLinkageName));
+  if (!FuncInfo.TryBlockMap.empty())
+    TryBlockMapXData = Asm->OutContext.GetOrCreateSymbol(
+        Twine("$tryMap$", ParentLinkageName));
+  if (!FuncInfo.IPToStateList.empty())
+    IPToStateXData = Asm->OutContext.GetOrCreateSymbol(
+        Twine("$ip2state$", ParentLinkageName));
+
+  // FuncInfo {
+  //   uint32_t           MagicNumber
+  //   int32_t            MaxState;
+  //   UnwindMapEntry    *UnwindMap;
+  //   uint32_t           NumTryBlocks;
+  //   TryBlockMapEntry  *TryBlockMap;
+  //   uint32_t           IPMapEntries;
+  //   IPToStateMapEntry *IPToStateMap;
+  //   uint32_t           UnwindHelp; // (x64/ARM only)
+  //   ESTypeList        *ESTypeList;
+  //   int32_t            EHFlags;
+  // }
+  // EHFlags & 1 -> Synchronous exceptions only, no async exceptions.
+  // EHFlags & 2 -> ???
+  // EHFlags & 4 -> The function is noexcept(true), unwinding can't continue.
+  OS.EmitLabel(FuncInfoXData);
+  OS.EmitIntValue(0x19930522, 4);                      // MagicNumber
+  OS.EmitIntValue(FuncInfo.UnwindMap.size(), 4);       // MaxState
+  OS.EmitValue(createImageRel32(UnwindMapXData), 4);   // UnwindMap
+  OS.EmitIntValue(FuncInfo.TryBlockMap.size(), 4);     // NumTryBlocks
+  OS.EmitValue(createImageRel32(TryBlockMapXData), 4); // TryBlockMap
+  OS.EmitIntValue(FuncInfo.IPToStateList.size(), 4);   // IPMapEntries
+  OS.EmitValue(createImageRel32(IPToStateXData), 4);   // IPToStateMap
+  OS.EmitIntValue(FuncInfo.UnwindHelpFrameOffset, 4);  // UnwindHelp
+  OS.EmitIntValue(0, 4);                               // ESTypeList
+  OS.EmitIntValue(1, 4);                               // EHFlags
+
+  // UnwindMapEntry {
+  //   int32_t ToState;
+  //   void  (*Action)();
+  // };
+  if (UnwindMapXData) {
+    OS.EmitLabel(UnwindMapXData);
+    for (const WinEHUnwindMapEntry &UME : FuncInfo.UnwindMap) {
+      OS.EmitIntValue(UME.ToState, 4);                // ToState
+      OS.EmitValue(createImageRel32(UME.Cleanup), 4); // Action
+    }
+  }
+
+  // TryBlockMap {
+  //   int32_t      TryLow;
+  //   int32_t      TryHigh;
+  //   int32_t      CatchHigh;
+  //   int32_t      NumCatches;
+  //   HandlerType *HandlerArray;
+  // };
+  if (TryBlockMapXData) {
+    OS.EmitLabel(TryBlockMapXData);
+    SmallVector<MCSymbol *, 1> HandlerMaps;
+    for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) {
+      WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I];
+      MCSymbol *HandlerMapXData = nullptr;
+
+      if (!TBME.HandlerArray.empty())
+        HandlerMapXData =
+            Asm->OutContext.GetOrCreateSymbol(Twine("$handlerMap$")
+                                                  .concat(Twine(I))
+                                                  .concat("$")
+                                                  .concat(ParentLinkageName));
+
+      HandlerMaps.push_back(HandlerMapXData);
+
+      assert(TBME.TryLow <= TBME.TryHigh);
+      assert(TBME.CatchHigh > TBME.TryHigh);
+      OS.EmitIntValue(TBME.TryLow, 4);                    // TryLow
+      OS.EmitIntValue(TBME.TryHigh, 4);                   // TryHigh
+      OS.EmitIntValue(TBME.CatchHigh, 4);                 // CatchHigh
+      OS.EmitIntValue(TBME.HandlerArray.size(), 4);       // NumCatches
+      OS.EmitValue(createImageRel32(HandlerMapXData), 4); // HandlerArray
+    }
+
+    for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) {
+      WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I];
+      MCSymbol *HandlerMapXData = HandlerMaps[I];
+      if (!HandlerMapXData)
+        continue;
+      // HandlerType {
+      //   int32_t         Adjectives;
+      //   TypeDescriptor *Type;
+      //   int32_t         CatchObjOffset;
+      //   void          (*Handler)();
+      //   int32_t         ParentFrameOffset; // x64 only
+      // };
+      OS.EmitLabel(HandlerMapXData);
+      for (const WinEHHandlerType &HT : TBME.HandlerArray) {
+        OS.EmitIntValue(HT.Adjectives, 4);                    // Adjectives
+        OS.EmitValue(createImageRel32(HT.TypeDescriptor), 4); // Type
+        OS.EmitIntValue(0, 4);                                // CatchObjOffset
+        OS.EmitValue(createImageRel32(HT.Handler), 4);        // Handler
+        OS.EmitIntValue(0, 4);                                // ParentFrameOffset
+      }
+    }
+  }
+
+  // IPToStateMapEntry {
+  //   void   *IP;
+  //   int32_t State;
+  // };
+  if (IPToStateXData) {
+    OS.EmitLabel(IPToStateXData);
+    for (auto &IPStatePair : FuncInfo.IPToStateList) {
+      OS.EmitValue(createImageRel32(IPStatePair.first), 4); // IP
+      OS.EmitIntValue(IPStatePair.second, 4);               // State
+    }
+  }
+}

+ 6 - 1
lib/CodeGen/AsmPrinter/Win64Exception.h

@@ -17,7 +17,9 @@
 #include "EHStreamer.h"
 #include "EHStreamer.h"
 
 
 namespace llvm {
 namespace llvm {
+class GlobalValue;
 class MachineFunction;
 class MachineFunction;
+class MCExpr;
 
 
 class Win64Exception : public EHStreamer {
 class Win64Exception : public EHStreamer {
   /// Per-function flag to indicate if personality info should be emitted.
   /// Per-function flag to indicate if personality info should be emitted.
@@ -31,7 +33,10 @@ class Win64Exception : public EHStreamer {
 
 
   void emitCSpecificHandlerTable();
   void emitCSpecificHandlerTable();
 
 
-  const MCSymbolRefExpr *createImageRel32(const MCSymbol *Value);
+  void emitCXXFrameHandler3Table(const MachineFunction *MF);
+
+  const MCExpr *createImageRel32(const MCSymbol *Value);
+  const MCExpr *createImageRel32(const GlobalValue *GV);
 
 
 public:
 public:
   //===--------------------------------------------------------------------===//
   //===--------------------------------------------------------------------===//

+ 22 - 0
lib/CodeGen/MachineModuleInfo.cpp

@@ -14,6 +14,7 @@
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
 #include "llvm/CodeGen/Passes.h"
 #include "llvm/CodeGen/Passes.h"
+#include "llvm/CodeGen/WinEHFuncInfo.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/GlobalVariable.h"
 #include "llvm/IR/GlobalVariable.h"
@@ -425,6 +426,12 @@ void MachineModuleInfo::addPersonality(MachineBasicBlock *LandingPad,
     Personalities.push_back(Personality);
     Personalities.push_back(Personality);
 }
 }
 
 
+void MachineModuleInfo::addWinEHState(MachineBasicBlock *LandingPad,
+                                      int State) {
+  LandingPadInfo &LP = getOrCreateLandingPadInfo(LandingPad);
+  LP.WinEHState = State;
+}
+
 /// addCatchTypeInfo - Provide the catch typeinfo for a landing pad.
 /// addCatchTypeInfo - Provide the catch typeinfo for a landing pad.
 ///
 ///
 void MachineModuleInfo::
 void MachineModuleInfo::
@@ -588,3 +595,18 @@ unsigned MachineModuleInfo::getPersonalityIndex() const {
   // in the zero index.
   // in the zero index.
   return 0;
   return 0;
 }
 }
+
+const Function *MachineModuleInfo::getWinEHParent(const Function *F) const {
+  StringRef WinEHParentName =
+      F->getFnAttribute("wineh-parent").getValueAsString();
+  if (WinEHParentName.empty() || WinEHParentName == F->getName())
+    return F;
+  return F->getParent()->getFunction(WinEHParentName);
+}
+
+WinEHFuncInfo &MachineModuleInfo::getWinEHFuncInfo(const Function *F) {
+  auto &Ptr = FuncInfoMap[getWinEHParent(F)];
+  if (!Ptr)
+    Ptr.reset(new WinEHFuncInfo);
+  return *Ptr;
+}

+ 20 - 0
lib/CodeGen/PrologEpilogInserter.cpp

@@ -30,6 +30,7 @@
 #include "llvm/CodeGen/Passes.h"
 #include "llvm/CodeGen/Passes.h"
 #include "llvm/CodeGen/RegisterScavenging.h"
 #include "llvm/CodeGen/RegisterScavenging.h"
 #include "llvm/CodeGen/StackProtector.h"
 #include "llvm/CodeGen/StackProtector.h"
+#include "llvm/CodeGen/WinEHFuncInfo.h"
 #include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/IR/InlineAsm.h"
 #include "llvm/IR/InlineAsm.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/LLVMContext.h"
@@ -752,6 +753,25 @@ void PEI::replaceFrameIndices(MachineFunction &Fn) {
   const TargetFrameLowering &TFI = *Fn.getSubtarget().getFrameLowering();
   const TargetFrameLowering &TFI = *Fn.getSubtarget().getFrameLowering();
   if (!TFI.needsFrameIndexResolution(Fn)) return;
   if (!TFI.needsFrameIndexResolution(Fn)) return;
 
 
+  MachineModuleInfo &MMI = Fn.getMMI();
+  const Function *F = Fn.getFunction();
+  const Function *ParentF = MMI.getWinEHParent(F);
+  unsigned FrameReg;
+  if (F == ParentF) {
+    WinEHFuncInfo &FuncInfo = MMI.getWinEHFuncInfo(Fn.getFunction());
+    // FIXME: This should be unconditional but we have bugs in the preparation
+    // pass.
+    if (FuncInfo.UnwindHelpFrameIdx != INT_MAX)
+      FuncInfo.UnwindHelpFrameOffset = TFI.getFrameIndexReferenceFromSP(
+          Fn, FuncInfo.UnwindHelpFrameIdx, FrameReg);
+  } else if (MMI.hasWinEHFuncInfo(F)) {
+    WinEHFuncInfo &FuncInfo = MMI.getWinEHFuncInfo(Fn.getFunction());
+    auto I = FuncInfo.CatchHandlerParentFrameObjIdx.find(F);
+    if (I != FuncInfo.CatchHandlerParentFrameObjIdx.end())
+      FuncInfo.CatchHandlerParentFrameObjOffset[F] =
+          TFI.getFrameIndexReferenceFromSP(Fn, I->second, FrameReg);
+  }
+
   // Store SPAdj at exit of a basic block.
   // Store SPAdj at exit of a basic block.
   SmallVector<int, 8> SPState;
   SmallVector<int, 8> SPState;
   SPState.resize(Fn.getNumBlockIDs());
   SPState.resize(Fn.getNumBlockIDs());

+ 7 - 0
lib/CodeGen/SelectionDAG/FastISel.cpp

@@ -1079,6 +1079,13 @@ bool FastISel::selectIntrinsicCall(const IntrinsicInst *II) {
   // The donothing intrinsic does, well, nothing.
   // The donothing intrinsic does, well, nothing.
   case Intrinsic::donothing:
   case Intrinsic::donothing:
     return true;
     return true;
+  case Intrinsic::eh_actions: {
+    unsigned ResultReg = getRegForValue(UndefValue::get(II->getType()));
+    if (!ResultReg)
+      return false;
+    updateValueMap(II, ResultReg);
+    return true;
+  }
   case Intrinsic::dbg_declare: {
   case Intrinsic::dbg_declare: {
     const DbgDeclareInst *DI = cast<DbgDeclareInst>(II);
     const DbgDeclareInst *DI = cast<DbgDeclareInst>(II);
     DIVariable DIVar(DI->getVariable());
     DIVariable DIVar(DI->getVariable());

+ 143 - 2
lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp

@@ -20,6 +20,7 @@
 #include "llvm/CodeGen/MachineInstrBuilder.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
 #include "llvm/CodeGen/MachineModuleInfo.h"
 #include "llvm/CodeGen/MachineModuleInfo.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/WinEHFuncInfo.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/DerivedTypes.h"
@@ -79,12 +80,34 @@ static ISD::NodeType getPreferredExtendForValue(const Value *V) {
   return ExtendKind;
   return ExtendKind;
 }
 }
 
 
+namespace {
+struct WinEHNumbering {
+  WinEHNumbering(WinEHFuncInfo &FuncInfo) : FuncInfo(FuncInfo), NextState(0) {}
+
+  WinEHFuncInfo &FuncInfo;
+  int NextState;
+
+  SmallVector<ActionHandler *, 4> HandlerStack;
+
+  int currentEHNumber() const {
+    return HandlerStack.empty() ? -1 : HandlerStack.back()->getEHState();
+  }
+
+  void parseEHActions(const IntrinsicInst *II,
+                      SmallVectorImpl<ActionHandler *> &Actions);
+  void createUnwindMapEntry(int ToState, ActionHandler *AH);
+  void proccessCallSite(ArrayRef<ActionHandler *> Actions, ImmutableCallSite CS);
+  void calculateStateNumbers(const Function &F);
+};
+}
+
 void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
 void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
                                SelectionDAG *DAG) {
                                SelectionDAG *DAG) {
   Fn = &fn;
   Fn = &fn;
   MF = &mf;
   MF = &mf;
   TLI = MF->getSubtarget().getTargetLowering();
   TLI = MF->getSubtarget().getTargetLowering();
   RegInfo = &MF->getRegInfo();
   RegInfo = &MF->getRegInfo();
+  MachineModuleInfo &MMI = MF->getMMI();
 
 
   // Check whether the function can return without sret-demotion.
   // Check whether the function can return without sret-demotion.
   SmallVector<ISD::OutputArg, 4> Outs;
   SmallVector<ISD::OutputArg, 4> Outs;
@@ -178,7 +201,6 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
       // during the initial isel pass through the IR so that it is done
       // during the initial isel pass through the IR so that it is done
       // in a predictable order.
       // in a predictable order.
       if (const DbgDeclareInst *DI = dyn_cast<DbgDeclareInst>(I)) {
       if (const DbgDeclareInst *DI = dyn_cast<DbgDeclareInst>(I)) {
-        MachineModuleInfo &MMI = MF->getMMI();
         DIVariable DIVar(DI->getVariable());
         DIVariable DIVar(DI->getVariable());
         assert((!DIVar || DIVar.isVariable()) &&
         assert((!DIVar || DIVar.isVariable()) &&
           "Variable in DbgDeclareInst should be either null or a DIVariable.");
           "Variable in DbgDeclareInst should be either null or a DIVariable.");
@@ -250,8 +272,127 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
 
 
   // Mark landing pad blocks.
   // Mark landing pad blocks.
   for (BB = Fn->begin(); BB != EB; ++BB)
   for (BB = Fn->begin(); BB != EB; ++BB)
-    if (const InvokeInst *Invoke = dyn_cast<InvokeInst>(BB->getTerminator()))
+    if (const auto *Invoke = dyn_cast<InvokeInst>(BB->getTerminator()))
       MBBMap[Invoke->getSuccessor(1)]->setIsLandingPad();
       MBBMap[Invoke->getSuccessor(1)]->setIsLandingPad();
+
+  // Calculate EH numbers for WinEH.
+  if (fn.getFnAttribute("wineh-parent").getValueAsString() == fn.getName())
+    WinEHNumbering(MMI.getWinEHFuncInfo(&fn)).calculateStateNumbers(fn);
+}
+
+void WinEHNumbering::parseEHActions(const IntrinsicInst *II,
+                                    SmallVectorImpl<ActionHandler *> &Actions) {
+  for (unsigned I = 0, E = II->getNumArgOperands(); I != E;) {
+    uint64_t ActionKind =
+        cast<ConstantInt>(II->getArgOperand(I))->getZExtValue();
+    if (ActionKind == /*catch=*/1) {
+      auto *Selector = cast<Constant>(II->getArgOperand(I + 1));
+      Value *CatchObject = II->getArgOperand(I + 2);
+      Constant *Handler = cast<Constant>(II->getArgOperand(I + 3));
+      I += 4;
+      auto *CH = new CatchHandler(/*BB=*/nullptr, Selector, /*NextBB=*/nullptr);
+      CH->setExceptionVar(CatchObject);
+      CH->setHandlerBlockOrFunc(Handler);
+      Actions.push_back(CH);
+    } else {
+      assert(ActionKind == 0 && "expected a cleanup or a catch action!");
+      Constant *Handler = cast<Constant>(II->getArgOperand(I + 1));
+      I += 2;
+      auto *CH = new CleanupHandler(/*BB=*/nullptr);
+      CH->setHandlerBlockOrFunc(Handler);
+      Actions.push_back(CH);
+    }
+  }
+  std::reverse(Actions.begin(), Actions.end());
+}
+
+void WinEHNumbering::createUnwindMapEntry(int ToState, ActionHandler *AH) {
+  WinEHUnwindMapEntry UME;
+  UME.ToState = ToState;
+  if (auto *CH = dyn_cast<CleanupHandler>(AH))
+    UME.Cleanup = cast<Function>(CH->getHandlerBlockOrFunc());
+  else
+    UME.Cleanup = nullptr;
+  FuncInfo.UnwindMap.push_back(UME);
+}
+
+static void print_name(const Value *V) {
+  if (!V) {
+    DEBUG(dbgs() << "null");
+    return;
+  }
+
+  if (const auto *F = dyn_cast<Function>(V))
+    DEBUG(dbgs() << F->getName());
+  else
+    DEBUG(V->dump());
+}
+
+void WinEHNumbering::proccessCallSite(ArrayRef<ActionHandler *> Actions,
+                                      ImmutableCallSite CS) {
+  // float, int
+  // float, double, int
+  int FirstMismatch = 0;
+  for (int E = std::min(HandlerStack.size(), Actions.size()); FirstMismatch < E;
+       ++FirstMismatch) {
+    if (HandlerStack[FirstMismatch]->getHandlerBlockOrFunc() !=
+        Actions[FirstMismatch]->getHandlerBlockOrFunc())
+      break;
+    delete Actions[FirstMismatch];
+  }
+
+  // Don't recurse while we are looping over the handler stack.  Instead, defer
+  // the numbering of the catch handlers until we are done popping.
+  SmallVector<const Function *, 4> UnnumberedHandlers;
+  for (int I = HandlerStack.size() - 1; I >= FirstMismatch; --I) {
+    if (auto *CH = dyn_cast<CatchHandler>(HandlerStack.back()))
+      if (const auto *F = dyn_cast<Function>(CH->getHandlerBlockOrFunc()))
+        UnnumberedHandlers.push_back(F);
+    // Pop the handlers off of the stack.
+    delete HandlerStack.back();
+    HandlerStack.pop_back();
+  }
+
+  for (const Function *F : UnnumberedHandlers)
+    calculateStateNumbers(*F);
+
+  for (size_t I = FirstMismatch; I != Actions.size(); ++I) {
+    createUnwindMapEntry(currentEHNumber(), Actions[I]);
+    Actions[I]->setEHState(NextState++);
+    DEBUG(dbgs() << "Creating unwind map entry for: (");
+    print_name(Actions[I]->getHandlerBlockOrFunc());
+    DEBUG(dbgs() << ", " << currentEHNumber() << ")\n");
+    HandlerStack.push_back(Actions[I]);
+  }
+
+  DEBUG(dbgs() << "In EHState " << currentEHNumber() << " for CallSite: ");
+  print_name(CS ? CS.getCalledValue() : nullptr);
+  DEBUG(dbgs() << '\n');
+}
+
+void WinEHNumbering::calculateStateNumbers(const Function &F) {
+  DEBUG(dbgs() << "Calculating state numbers for: " << F.getName() << '\n');
+  SmallVector<ActionHandler *, 4> ActionList;
+  for (const BasicBlock &BB : F) {
+    for (const Instruction &I : BB) {
+      const auto *CI = dyn_cast<CallInst>(&I);
+      if (!CI || CI->doesNotThrow())
+        continue;
+      proccessCallSite(None, CI);
+    }
+    const auto *II = dyn_cast<InvokeInst>(BB.getTerminator());
+    if (!II)
+      continue;
+    const LandingPadInst *LPI = II->getLandingPadInst();
+    if (auto *ActionsCall = dyn_cast<IntrinsicInst>(LPI->getNextNode())) {
+      assert(ActionsCall->getIntrinsicID() == Intrinsic::eh_actions);
+      parseEHActions(ActionsCall, ActionList);
+      proccessCallSite(ActionList, II);
+      ActionList.clear();
+      FuncInfo.LandingPadStateMap[LPI] = currentEHNumber();
+    }
+  }
+  proccessCallSite(None, ImmutableCallSite());
 }
 }
 
 
 /// clear - Clear out all the function-specific state. This returns this
 /// clear - Clear out all the function-specific state. This returns this

+ 11 - 4
lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp

@@ -35,6 +35,7 @@
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/SelectionDAG.h"
 #include "llvm/CodeGen/SelectionDAG.h"
 #include "llvm/CodeGen/StackMaps.h"
 #include "llvm/CodeGen/StackMaps.h"
+#include "llvm/CodeGen/WinEHFuncInfo.h"
 #include "llvm/IR/CallingConv.h"
 #include "llvm/IR/CallingConv.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DataLayout.h"
@@ -5360,6 +5361,9 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
   }
   }
   case Intrinsic::clear_cache:
   case Intrinsic::clear_cache:
     return TLI.getClearCacheBuiltinName();
     return TLI.getClearCacheBuiltinName();
+  case Intrinsic::eh_actions:
+    setValue(&I, DAG.getUNDEF(TLI.getPointerTy()));
+    return nullptr;
   case Intrinsic::donothing:
   case Intrinsic::donothing:
     // ignore
     // ignore
     return nullptr;
     return nullptr;
@@ -5452,8 +5456,10 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
     assert(FuncInfo.StaticAllocaMap.count(Slot) &&
     assert(FuncInfo.StaticAllocaMap.count(Slot) &&
            "can only use static allocas with llvm.eh.parentframe");
            "can only use static allocas with llvm.eh.parentframe");
     int FI = FuncInfo.StaticAllocaMap[Slot];
     int FI = FuncInfo.StaticAllocaMap[Slot];
-    // TODO: Save this in the not-yet-existent WinEHFuncInfo struct.
-    (void)FI;
+    MachineFunction &MF = DAG.getMachineFunction();
+    const Function *F = MF.getFunction();
+    MachineModuleInfo &MMI = MF.getMMI();
+    MMI.getWinEHFuncInfo(F).CatchHandlerParentFrameObjIdx[F] = FI;
     return nullptr;
     return nullptr;
   }
   }
   case Intrinsic::eh_unwindhelp: {
   case Intrinsic::eh_unwindhelp: {
@@ -5462,8 +5468,9 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
     assert(FuncInfo.StaticAllocaMap.count(Slot) &&
     assert(FuncInfo.StaticAllocaMap.count(Slot) &&
            "can only use static allocas with llvm.eh.unwindhelp");
            "can only use static allocas with llvm.eh.unwindhelp");
     int FI = FuncInfo.StaticAllocaMap[Slot];
     int FI = FuncInfo.StaticAllocaMap[Slot];
-    // TODO: Save this in the not-yet-existent WinEHFuncInfo struct.
-    (void)FI;
+    MachineFunction &MF = DAG.getMachineFunction();
+    MachineModuleInfo &MMI = MF.getMMI();
+    MMI.getWinEHFuncInfo(MF.getFunction()).UnwindHelpFrameIdx = FI;
     return nullptr;
     return nullptr;
   }
   }
   }
   }

+ 5 - 0
lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp

@@ -33,6 +33,7 @@
 #include "llvm/CodeGen/SchedulerRegistry.h"
 #include "llvm/CodeGen/SchedulerRegistry.h"
 #include "llvm/CodeGen/SelectionDAG.h"
 #include "llvm/CodeGen/SelectionDAG.h"
 #include "llvm/CodeGen/SelectionDAGISel.h"
 #include "llvm/CodeGen/SelectionDAGISel.h"
+#include "llvm/CodeGen/WinEHFuncInfo.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/Function.h"
@@ -988,6 +989,10 @@ void SelectionDAGISel::PrepareEHLandingPad() {
     FuncInfo->InsertPt = MBB->end();
     FuncInfo->InsertPt = MBB->end();
     return;
     return;
   }
   }
+  if (MF->getMMI().getPersonalityType() == EHPersonality::MSVC_CXX) {
+    WinEHFuncInfo &FuncInfo = MF->getMMI().getWinEHFuncInfo(MF->getFunction());
+    MF->getMMI().addWinEHState(MBB, FuncInfo.LandingPadStateMap[LPadInst]);
+  }
 
 
   // Mark exception register as live in.
   // Mark exception register as live in.
   if (unsigned Reg = TLI->getExceptionPointerRegister())
   if (unsigned Reg = TLI->getExceptionPointerRegister())

+ 9 - 67
lib/CodeGen/WinEHPrepare.cpp

@@ -20,6 +20,7 @@
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/TinyPtrVector.h"
 #include "llvm/ADT/TinyPtrVector.h"
 #include "llvm/Analysis/LibCallSemantics.h"
 #include "llvm/Analysis/LibCallSemantics.h"
+#include "llvm/CodeGen/WinEHFuncInfo.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/Instructions.h"
@@ -51,12 +52,7 @@ typedef MapVector<Value *, TinyPtrVector<AllocaInst *>> FrameVarInfoMap;
 
 
 typedef SmallSet<BasicBlock *, 4> VisitedBlockSet;
 typedef SmallSet<BasicBlock *, 4> VisitedBlockSet;
 
 
-enum ActionType { Catch, Cleanup };
-
 class LandingPadActions;
 class LandingPadActions;
-class ActionHandler;
-class CatchHandler;
-class CleanupHandler;
 class LandingPadMap;
 class LandingPadMap;
 
 
 typedef DenseMap<const BasicBlock *, CatchHandler *> CatchHandlerMapTy;
 typedef DenseMap<const BasicBlock *, CatchHandler *> CatchHandlerMapTy;
@@ -242,66 +238,6 @@ public:
                              BasicBlock *NewBB) override;
                              BasicBlock *NewBB) override;
 };
 };
 
 
-class ActionHandler {
-public:
-  ActionHandler(BasicBlock *BB, ActionType Type)
-      : StartBB(BB), Type(Type), HandlerBlockOrFunc(nullptr) {}
-
-  ActionType getType() const { return Type; }
-  BasicBlock *getStartBlock() const { return StartBB; }
-
-  bool hasBeenProcessed() { return HandlerBlockOrFunc != nullptr; }
-
-  void setHandlerBlockOrFunc(Constant *F) { HandlerBlockOrFunc = F; }
-  Constant *getHandlerBlockOrFunc() { return HandlerBlockOrFunc; }
-
-private:
-  BasicBlock *StartBB;
-  ActionType Type;
-
-  // Can be either a BlockAddress or a Function depending on the EH personality.
-  Constant *HandlerBlockOrFunc;
-};
-
-class CatchHandler : public ActionHandler {
-public:
-  CatchHandler(BasicBlock *BB, Constant *Selector, BasicBlock *NextBB)
-      : ActionHandler(BB, ActionType::Catch), Selector(Selector),
-        NextBB(NextBB), ExceptionObjectVar(nullptr) {}
-
-  // Method for support type inquiry through isa, cast, and dyn_cast:
-  static inline bool classof(const ActionHandler *H) {
-    return H->getType() == ActionType::Catch;
-  }
-
-  Constant *getSelector() const { return Selector; }
-  BasicBlock *getNextBB() const { return NextBB; }
-
-  const Value *getExceptionVar() { return ExceptionObjectVar; }
-  TinyPtrVector<BasicBlock *> &getReturnTargets() { return ReturnTargets; }
-
-  void setExceptionVar(const Value *Val) { ExceptionObjectVar = Val; }
-  void setReturnTargets(TinyPtrVector<BasicBlock *> &Targets) {
-    ReturnTargets = Targets;
-  }
-
-private:
-  Constant *Selector;
-  BasicBlock *NextBB;
-  const Value *ExceptionObjectVar;
-  TinyPtrVector<BasicBlock *> ReturnTargets;
-};
-
-class CleanupHandler : public ActionHandler {
-public:
-  CleanupHandler(BasicBlock *BB) : ActionHandler(BB, ActionType::Cleanup) {}
-
-  // Method for support type inquiry through isa, cast, and dyn_cast:
-  static inline bool classof(const ActionHandler *H) {
-    return H->getType() == ActionType::Cleanup;
-  }
-};
-
 class LandingPadActions {
 class LandingPadActions {
 public:
 public:
   LandingPadActions() : HasCleanupHandlers(false) {}
   LandingPadActions() : HasCleanupHandlers(false) {}
@@ -314,6 +250,7 @@ public:
 
 
   bool includesCleanup() const { return HasCleanupHandlers; }
   bool includesCleanup() const { return HasCleanupHandlers; }
 
 
+  SmallVectorImpl<ActionHandler *> &actions() { return Actions; }
   SmallVectorImpl<ActionHandler *>::iterator begin() { return Actions.begin(); }
   SmallVectorImpl<ActionHandler *>::iterator begin() { return Actions.begin(); }
   SmallVectorImpl<ActionHandler *>::iterator end() { return Actions.end(); }
   SmallVectorImpl<ActionHandler *>::iterator end() { return Actions.end(); }
 
 
@@ -454,7 +391,7 @@ bool WinEHPrepare::prepareExceptionHandlers(
     // Replace the landing pad with a new llvm.eh.action based landing pad.
     // Replace the landing pad with a new llvm.eh.action based landing pad.
     BasicBlock *NewLPadBB = BasicBlock::Create(Context, "lpad", &F, LPadBB);
     BasicBlock *NewLPadBB = BasicBlock::Create(Context, "lpad", &F, LPadBB);
     assert(!isa<PHINode>(LPadBB->begin()));
     assert(!isa<PHINode>(LPadBB->begin()));
-    Instruction *NewLPad = LPad->clone();
+    auto *NewLPad = cast<LandingPadInst>(LPad->clone());
     NewLPadBB->getInstList().push_back(NewLPad);
     NewLPadBB->getInstList().push_back(NewLPad);
     while (!pred_empty(LPadBB)) {
     while (!pred_empty(LPadBB)) {
       auto *pred = *pred_begin(LPadBB);
       auto *pred = *pred_begin(LPadBB);
@@ -503,6 +440,8 @@ bool WinEHPrepare::prepareExceptionHandlers(
   if (!HandlersOutlined)
   if (!HandlersOutlined)
     return false;
     return false;
 
 
+  F.addFnAttr("wineh-parent", F.getName());
+
   // Delete any blocks that were only used by handlers that were outlined above.
   // Delete any blocks that were only used by handlers that were outlined above.
   removeUnreachableBlocks(F);
   removeUnreachableBlocks(F);
 
 
@@ -609,7 +548,8 @@ bool WinEHPrepare::prepareExceptionHandlers(
   Type *UnwindHelpTy = Type::getInt64Ty(Context);
   Type *UnwindHelpTy = Type::getInt64Ty(Context);
   AllocaInst *UnwindHelp =
   AllocaInst *UnwindHelp =
       new AllocaInst(UnwindHelpTy, "unwindhelp", &F.getEntryBlock().front());
       new AllocaInst(UnwindHelpTy, "unwindhelp", &F.getEntryBlock().front());
-  Builder.CreateStore(llvm::ConstantInt::get(UnwindHelpTy, -2), UnwindHelp);
+  Builder.CreateStore(llvm::ConstantInt::get(UnwindHelpTy, -2), UnwindHelp,
+                      /*isVolatile=*/true);
   Function *UnwindHelpFn =
   Function *UnwindHelpFn =
       Intrinsic::getDeclaration(M, Intrinsic::eh_unwindhelp);
       Intrinsic::getDeclaration(M, Intrinsic::eh_unwindhelp);
   Builder.CreateCall(UnwindHelpFn,
   Builder.CreateCall(UnwindHelpFn,
@@ -681,6 +621,8 @@ bool WinEHPrepare::outlineHandler(ActionHandler *Action, Function *SrcFn,
                                SrcFn->getName() + ".cleanup", M);
                                SrcFn->getName() + ".cleanup", M);
   }
   }
 
 
+  Handler->addFnAttr("wineh-parent", SrcFn->getName());
+
   // Generate a standard prolog to setup the frame recovery structure.
   // Generate a standard prolog to setup the frame recovery structure.
   IRBuilder<> Builder(Context);
   IRBuilder<> Builder(Context);
   BasicBlock *Entry = BasicBlock::Create(Context, "entry");
   BasicBlock *Entry = BasicBlock::Create(Context, "entry");

+ 2 - 2
test/CodeGen/WinEH/cppeh-catch-all.ll

@@ -19,7 +19,7 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-pc-windows-msvc"
 target triple = "x86_64-pc-windows-msvc"
 
 
 ; The function entry in this case remains unchanged.
 ; The function entry in this case remains unchanged.
-; CHECK: define void @_Z4testv() #0 {
+; CHECK: define void @_Z4testv()
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   invoke void @_Z9may_throwv()
 ; CHECK:   invoke void @_Z9may_throwv()
 ; CHECK:           to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]+]]
 ; CHECK:           to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]+]]
@@ -70,7 +70,7 @@ try.cont:                                         ; preds = %invoke.cont2, %invo
 ; CHECK: }
 ; CHECK: }
 }
 }
 
 
-; CHECK: define internal i8* @_Z4testv.catch(i8*, i8*) {
+; CHECK: define internal i8* @_Z4testv.catch(i8*, i8*)
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   call void @_Z16handle_exceptionv()
 ; CHECK:   call void @_Z16handle_exceptionv()
 ; CHECK:   ret i8* blockaddress(@_Z4testv, %try.cont)
 ; CHECK:   ret i8* blockaddress(@_Z4testv, %try.cont)

+ 2 - 2
test/CodeGen/WinEH/cppeh-catch-scalar.ll

@@ -21,7 +21,7 @@ target triple = "x86_64-pc-windows-msvc"
 @_ZTIi = external constant i8*
 @_ZTIi = external constant i8*
 
 
 ; The function entry will be rewritten like this.
 ; The function entry will be rewritten like this.
-; CHECK: define void @_Z4testv() #0 {
+; CHECK: define void @_Z4testv()
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   [[I_PTR:\%.+]] = alloca i32, align 4
 ; CHECK:   [[I_PTR:\%.+]] = alloca i32, align 4
 ; CHECK:   call void (...)* @llvm.frameescape(i32* [[I_PTR]])
 ; CHECK:   call void (...)* @llvm.frameescape(i32* [[I_PTR]])
@@ -94,7 +94,7 @@ eh.resume:                                        ; preds = %catch.dispatch
 ; CHECK: }
 ; CHECK: }
 }
 }
 
 
-; CHECK: define internal i8* @_Z4testv.catch(i8*, i8*) {
+; CHECK: define internal i8* @_Z4testv.catch(i8*, i8*)
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   [[RECOVER_I:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 0)
 ; CHECK:   [[RECOVER_I:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 0)
 ; CHECK:   [[I_PTR1:\%.+]] = bitcast i8* [[RECOVER_I]] to i32*
 ; CHECK:   [[I_PTR1:\%.+]] = bitcast i8* [[RECOVER_I]] to i32*

+ 4 - 4
test/CodeGen/WinEH/cppeh-catch-unwind.ll

@@ -178,7 +178,7 @@ eh.resume:                                        ; preds = %catch.dispatch7
 ; CHECK: }
 ; CHECK: }
 }
 }
 
 
-; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) {
+; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*)
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   [[PARENTFRAME:\%.+]] = alloca i8*
 ; CHECK:   [[PARENTFRAME:\%.+]] = alloca i8*
 ; CHECK:   store volatile i8* %1, i8** [[PARENTFRAME]]
 ; CHECK:   store volatile i8* %1, i8** [[PARENTFRAME]]
@@ -189,15 +189,15 @@ eh.resume:                                        ; preds = %catch.dispatch7
 ; CHECK:   ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont15)
 ; CHECK:   ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont15)
 ; CHECK: }
 ; CHECK: }
 
 
-; CHECK-LABEL: define internal void @"\01?test@@YAXXZ.cleanup"(i8*, i8*) {
+; CHECK-LABEL: define internal void @"\01?test@@YAXXZ.cleanup"(i8*, i8*)
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   [[RECOVER_OBJ:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1)
 ; CHECK:   [[RECOVER_OBJ:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1)
 ; CHECK:   [[OBJ_PTR:\%.+]] = bitcast i8* %obj.i8 to %class.SomeClass*
 ; CHECK:   [[OBJ_PTR:\%.+]] = bitcast i8* %obj.i8 to %class.SomeClass*
-; CHECK:   call void @"\01??1SomeClass@@QEAA@XZ"(%class.SomeClass* [[OBJ_PTR]]) #3
+; CHECK:   call void @"\01??1SomeClass@@QEAA@XZ"(%class.SomeClass* [[OBJ_PTR]])
 ; CHECK:   ret void
 ; CHECK:   ret void
 ; CHECK: }
 ; CHECK: }
 
 
-; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch1"(i8*, i8*) {
+; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch1"(i8*, i8*)
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   [[PARENTFRAME:\%.+]] = alloca i8*
 ; CHECK:   [[PARENTFRAME:\%.+]] = alloca i8*
 ; CHECK:   store volatile i8* %1, i8** [[PARENTFRAME]]
 ; CHECK:   store volatile i8* %1, i8** [[PARENTFRAME]]

+ 226 - 0
test/CodeGen/WinEH/cppeh-cleanups.ll

@@ -0,0 +1,226 @@
+; RUN: llc < %s | FileCheck %s
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-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.S = type { i8 }
+
+$"\01??_DS@@QEAA@XZ" = comdat any
+
+$"\01??_R0H@8" = comdat any
+
+$"_CT??_R0H@84" = comdat any
+
+$_CTA1H = comdat any
+
+$_TI1H = comdat any
+
+@"\01??_7type_info@@6B@" = external constant i8*
+@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
+@__ImageBase = external constant i8
+@"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"\01??_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
+@_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
+@_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
+
+
+; CHECK-LABEL: ?test1@@YAXXZ":
+; CHECK:             .seh_handlerdata
+; CHECK-NEXT:        .long   ("$cppxdata$?test1@@YAXXZ")@IMGREL
+; CHECK-NEXT:"$cppxdata$?test1@@YAXXZ":
+; CHECK-NEXT:        .long   429065506
+; CHECK-NEXT:        .long   1
+; CHECK-NEXT:        .long   ("$stateUnwindMap$?test1@@YAXXZ")@IMGREL
+; CHECK-NEXT:        .long   0
+; CHECK-NEXT:        .long   0
+; CHECK-NEXT:        .long   1
+; CHECK-NEXT:        .long   ("$ip2state$?test1@@YAXXZ")@IMGREL
+; CHECK-NEXT:        .long   64
+; CHECK-NEXT:        .long   0
+; CHECK-NEXT:        .long   1
+; CHECK-NEXT:"$stateUnwindMap$?test1@@YAXXZ":
+; CHECK-NEXT:        .long   -1
+; CHECK-NEXT:        .long   "?test1@@YAXXZ.cleanup"@IMGREL
+; CHECK-NEXT:"$ip2state$?test1@@YAXXZ":
+; CHECK-NEXT:        .long   .Ltmp0@IMGREL
+; CHECK-NEXT:        .long   0
+
+define void @"\01?test1@@YAXXZ"() #0 {
+entry:
+  %unwindhelp = alloca i64
+  %tmp = alloca i32, align 4
+  %exn.slot = alloca i8*
+  %ehselector.slot = alloca i32
+  store i32 0, i32* %tmp
+  %0 = bitcast i32* %tmp to i8*
+  call void (...)* @llvm.frameescape()
+  store volatile i64 -2, i64* %unwindhelp
+  %1 = bitcast i64* %unwindhelp to i8*
+  call void @llvm.eh.unwindhelp(i8* %1)
+  invoke void @_CxxThrowException(i8* %0, %eh.ThrowInfo* @_TI1H) #8
+          to label %unreachable unwind label %lpad1
+
+lpad1:                                            ; preds = %entry
+  %2 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
+          cleanup
+  %recover = call i8* (...)* @llvm.eh.actions(i32 0, void (i8*, i8*)* @"\01?test1@@YAXXZ.cleanup")
+  indirectbr i8* %recover, []
+
+unreachable:                                      ; preds = %entry
+  unreachable
+}
+
+declare void @_CxxThrowException(i8*, %eh.ThrowInfo*)
+
+declare i32 @__CxxFrameHandler3(...)
+
+; Function Attrs: nounwind
+define linkonce_odr void @"\01??_DS@@QEAA@XZ"(%struct.S* %this) unnamed_addr #1 comdat align 2 {
+entry:
+  %this.addr = alloca %struct.S*, align 8
+  store %struct.S* %this, %struct.S** %this.addr, align 8
+  %this1 = load %struct.S*, %struct.S** %this.addr
+  call void @"\01??1S@@QEAA@XZ"(%struct.S* %this1) #4
+  ret void
+}
+
+; CHECK-LABEL: "?test2@@YAX_N@Z":
+; CHECK:             .seh_handlerdata
+; CHECK-NEXT:        .long   ("$cppxdata$?test2@@YAX_N@Z")@IMGREL
+; CHECK-NEXT:"$cppxdata$?test2@@YAX_N@Z":
+; CHECK-NEXT:        .long   429065506
+; CHECK-NEXT:        .long   2
+; CHECK-NEXT:        .long   ("$stateUnwindMap$?test2@@YAX_N@Z")@IMGREL
+; CHECK-NEXT:        .long   0
+; CHECK-NEXT:        .long   0
+; CHECK-NEXT:        .long   4
+; CHECK-NEXT:        .long   ("$ip2state$?test2@@YAX_N@Z")@IMGREL
+; CHECK-NEXT:        .long   64
+; CHECK-NEXT:        .long   0
+; CHECK-NEXT:        .long   1
+; CHECK-NEXT:"$stateUnwindMap$?test2@@YAX_N@Z":
+; CHECK-NEXT:        .long   -1
+; CHECK-NEXT:        .long   "?test2@@YAX_N@Z.cleanup"@IMGREL
+; CHECK-NEXT:        .long   0
+; CHECK-NEXT:        .long   "?test2@@YAX_N@Z.cleanup1"@IMGREL
+; CHECK-NEXT:"$ip2state$?test2@@YAX_N@Z":
+; CHECK-NEXT:        .long   .Lfunc_begin1@IMGREL
+; CHECK-NEXT:        .long   -1
+; CHECK-NEXT:        .long   .Ltmp7@IMGREL
+; CHECK-NEXT:        .long   0
+; CHECK-NEXT:        .long   .Ltmp9@IMGREL
+; CHECK-NEXT:        .long   1
+; CHECK-NEXT:        .long   .Ltmp12@IMGREL
+; CHECK-NEXT:        .long   0
+
+define void @"\01?test2@@YAX_N@Z"(i1 zeroext %b) #2 {
+entry:
+  %unwindhelp = alloca i64
+  %b.addr = alloca i8, align 1
+  %s = alloca %struct.S, align 1
+  %exn.slot = alloca i8*
+  %ehselector.slot = alloca i32
+  %s1 = alloca %struct.S, align 1
+  %frombool = zext i1 %b to i8
+  store i8 %frombool, i8* %b.addr, align 1
+  call void @"\01?may_throw@@YAXXZ"()
+  call void (...)* @llvm.frameescape(%struct.S* %s, %struct.S* %s1)
+  store volatile i64 -2, i64* %unwindhelp
+  %0 = bitcast i64* %unwindhelp to i8*
+  call void @llvm.eh.unwindhelp(i8* %0)
+  invoke void @"\01?may_throw@@YAXXZ"()
+          to label %invoke.cont unwind label %lpad1
+
+invoke.cont:                                      ; preds = %entry
+  %1 = load i8, i8* %b.addr, align 1
+  %tobool = trunc i8 %1 to i1
+  br i1 %tobool, label %if.then, label %if.else
+
+if.then:                                          ; preds = %invoke.cont
+  invoke void @"\01?may_throw@@YAXXZ"()
+          to label %invoke.cont3 unwind label %lpad3
+
+invoke.cont3:                                     ; preds = %if.then
+  call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s1) #4
+  br label %if.end
+
+lpad1:                                            ; preds = %entry, %if.end
+  %2 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
+          cleanup
+  %recover = call i8* (...)* @llvm.eh.actions(i32 0, void (i8*, i8*)* @"\01?test2@@YAX_N@Z.cleanup")
+  indirectbr i8* %recover, []
+
+lpad3:                                            ; preds = %if.then
+  %3 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
+          cleanup
+  %recover4 = call i8* (...)* @llvm.eh.actions(i32 0, void (i8*, i8*)* @"\01?test2@@YAX_N@Z.cleanup1", i32 0, void (i8*, i8*)* @"\01?test2@@YAX_N@Z.cleanup")
+  indirectbr i8* %recover4, []
+
+if.else:                                          ; preds = %invoke.cont
+  call void @"\01?dont_throw@@YAXXZ"() #4
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %invoke.cont3
+  invoke void @"\01?may_throw@@YAXXZ"()
+          to label %invoke.cont4 unwind label %lpad1
+
+invoke.cont4:                                     ; preds = %if.end
+  call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s) #4
+  ret void
+}
+
+declare void @"\01?may_throw@@YAXXZ"() #3
+
+; Function Attrs: nounwind
+declare void @"\01?dont_throw@@YAXXZ"() #1
+
+; Function Attrs: nounwind
+declare void @"\01??1S@@QEAA@XZ"(%struct.S*) #1
+
+; Function Attrs: nounwind
+declare i8* @llvm.eh.actions(...) #4
+
+define internal void @"\01?test1@@YAXXZ.cleanup"(i8*, i8*) #5 {
+entry:
+  %s = alloca %struct.S, align 1
+  call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s) #4
+  ret void
+}
+
+; Function Attrs: nounwind
+declare void @llvm.frameescape(...) #4
+
+; Function Attrs: nounwind readnone
+declare i8* @llvm.framerecover(i8*, i8*, i32) #6
+
+; Function Attrs: nounwind
+declare void @llvm.eh.unwindhelp(i8*) #4
+
+define internal void @"\01?test2@@YAX_N@Z.cleanup"(i8*, i8*) #7 {
+entry:
+  %s.i8 = call i8* @llvm.framerecover(i8* bitcast (void (i1)* @"\01?test2@@YAX_N@Z" to i8*), i8* %1, i32 0)
+  %s = bitcast i8* %s.i8 to %struct.S*
+  call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s) #4
+  ret void
+}
+
+define internal void @"\01?test2@@YAX_N@Z.cleanup1"(i8*, i8*) #7 {
+entry:
+  %s1.i8 = call i8* @llvm.framerecover(i8* bitcast (void (i1)* @"\01?test2@@YAX_N@Z" to i8*), i8* %1, i32 1)
+  %s1 = bitcast i8* %s1.i8 to %struct.S*
+  call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s1) #4
+  ret void
+}
+
+attributes #0 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" "wineh-parent"="?test1@@YAXXZ" }
+attributes #1 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" "wineh-parent"="?test2@@YAX_N@Z" }
+attributes #3 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #4 = { nounwind }
+attributes #5 = { "wineh-parent"="?test1@@YAXXZ" }
+attributes #6 = { nounwind readnone }
+attributes #7 = { "wineh-parent"="?test2@@YAX_N@Z" }
+attributes #8 = { noreturn }

+ 2 - 2
test/CodeGen/WinEH/cppeh-frame-vars.ll

@@ -47,7 +47,7 @@ $"\01??_R0H@8" = comdat any
 @"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
 @"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
 
 
 ; The function entry should be rewritten like this.
 ; The function entry should be rewritten like this.
-; CHECK: define void @"\01?test@@YAXXZ"() #0 {
+; CHECK: define void @"\01?test@@YAXXZ"()
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   [[NUMEXCEPTIONS_PTR:\%.+]] = alloca i32, align 4
 ; CHECK:   [[NUMEXCEPTIONS_PTR:\%.+]] = alloca i32, align 4
 ; CHECK:   [[EXCEPTIONVAL_PTR:\%.+]] = alloca [10 x i32], align 16
 ; CHECK:   [[EXCEPTIONVAL_PTR:\%.+]] = alloca [10 x i32], align 16
@@ -196,7 +196,7 @@ eh.resume:                                        ; preds = %catch.dispatch
 }
 }
 
 
 ; The following catch handler should be outlined.
 ; The following catch handler should be outlined.
-; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) {
+; CHECK-LABEL: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*)
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   [[RECOVER_E:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0)
 ; CHECK:   [[RECOVER_E:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0)
 ; CHECK:   [[E_PTR1:\%.+]] = bitcast i8* [[RECOVER_E]] to i32*
 ; CHECK:   [[E_PTR1:\%.+]] = bitcast i8* [[RECOVER_E]] to i32*

+ 3 - 3
test/CodeGen/WinEH/cppeh-inalloca.ll

@@ -36,7 +36,7 @@ $"\01??_R0H@8" = comdat any
 @"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
 @"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
 
 
 ; The function entry should be rewritten like this.
 ; The function entry should be rewritten like this.
-; CHECK: define i32 @"\01?test@@YAHUA@@@Z"(<{ %struct.A }>* inalloca) #0 {
+; CHECK: define i32 @"\01?test@@YAHUA@@@Z"(<{ %struct.A }>* inalloca)
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   [[TMP_REGMEM:\%.+]] = alloca <{ %struct.A }>*
 ; CHECK:   [[TMP_REGMEM:\%.+]] = alloca <{ %struct.A }>*
 ; CHECK:   [[TMP:\%.+]] = select i1 true, <{ %struct.A }>* %0, <{ %struct.A }>* undef
 ; CHECK:   [[TMP:\%.+]] = select i1 true, <{ %struct.A }>* %0, <{ %struct.A }>* undef
@@ -142,7 +142,7 @@ eh.resume:                                        ; preds = %ehcleanup
 }
 }
 
 
 ; The following catch handler should be outlined.
 ; The following catch handler should be outlined.
-; CHECK: define internal i8* @"\01?test@@YAHUA@@@Z.catch"(i8*, i8*) {
+; CHECK: define internal i8* @"\01?test@@YAHUA@@@Z.catch"(i8*, i8*)
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   [[RECOVER_E:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (i32 (<{ %struct.A }>*)* @"\01?test@@YAHUA@@@Z" to i8*), i8* %1, i32 0)
 ; CHECK:   [[RECOVER_E:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (i32 (<{ %struct.A }>*)* @"\01?test@@YAHUA@@@Z" to i8*), i8* %1, i32 0)
 ; CHECK:   [[E_PTR:\%.+]] = bitcast i8* [[RECOVER_E]] to i32*
 ; CHECK:   [[E_PTR:\%.+]] = bitcast i8* [[RECOVER_E]] to i32*
@@ -165,7 +165,7 @@ eh.resume:                                        ; preds = %ehcleanup
 ; CHECK: }
 ; CHECK: }
 
 
 ; The following cleanup handler should be outlined.
 ; The following cleanup handler should be outlined.
-; CHECK: define internal void @"\01?test@@YAHUA@@@Z.cleanup"(i8*, i8*) {
+; CHECK: define internal void @"\01?test@@YAHUA@@@Z.cleanup"(i8*, i8*)
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   [[RECOVER_EH_TEMP1:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (i32 (<{ %struct.A }>*)* @"\01?test@@YAHUA@@@Z" to i8*), i8* %1, i32 1)
 ; CHECK:   [[RECOVER_EH_TEMP1:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (i32 (<{ %struct.A }>*)* @"\01?test@@YAHUA@@@Z" to i8*), i8* %1, i32 1)
 ; CHECK:   [[EH_TEMP1:\%.+]] = bitcast i8* [[RECOVER_EH_TEMP]] to <{ %struct.A }>**
 ; CHECK:   [[EH_TEMP1:\%.+]] = bitcast i8* [[RECOVER_EH_TEMP]] to <{ %struct.A }>**

+ 2 - 2
test/CodeGen/WinEH/cppeh-min-unwind.ll

@@ -21,7 +21,7 @@ target triple = "x86_64-pc-windows-msvc"
 %class.SomeClass = type { [28 x i32] }
 %class.SomeClass = type { [28 x i32] }
 
 
 ; The function entry should be rewritten like this.
 ; The function entry should be rewritten like this.
-; CHECK: define void @_Z4testv() #0 {
+; CHECK: define void @_Z4testv()
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   [[OBJ_PTR:\%.+]] = alloca %class.SomeClass, align 4
 ; CHECK:   [[OBJ_PTR:\%.+]] = alloca %class.SomeClass, align 4
 ; CHECK:   call void @_ZN9SomeClassC1Ev(%class.SomeClass* [[OBJ_PTR]])
 ; CHECK:   call void @_ZN9SomeClassC1Ev(%class.SomeClass* [[OBJ_PTR]])
@@ -72,7 +72,7 @@ eh.resume:                                        ; preds = %lpad
 }
 }
 
 
 ; This cleanup handler should be outlined.
 ; This cleanup handler should be outlined.
-; CHECK: define internal void @_Z4testv.cleanup(i8*, i8*) {
+; CHECK: define internal void @_Z4testv.cleanup(i8*, i8*)
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   [[RECOVER_OBJ:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 0)
 ; CHECK:   [[RECOVER_OBJ:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 0)
 ; CHECK:   [[OBJ_PTR1:\%.+]] = bitcast i8* [[RECOVER_OBJ]] to %class.SomeClass*
 ; CHECK:   [[OBJ_PTR1:\%.+]] = bitcast i8* [[RECOVER_OBJ]] to %class.SomeClass*

+ 3 - 3
test/CodeGen/WinEH/cppeh-nested-1.ll

@@ -31,7 +31,7 @@ $"\01??_R0H@8" = comdat any
 @"\01??_R0M@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".M\00" }, comdat
 @"\01??_R0M@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".M\00" }, comdat
 @"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
 @"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
 
 
-; CHECK: define void @"\01?test@@YAXXZ"() #0 {
+; CHECK: define void @"\01?test@@YAXXZ"()
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   %i = alloca i32, align 4
 ; CHECK:   %i = alloca i32, align 4
 ; CHECK:   %f = alloca float, align 4
 ; CHECK:   %f = alloca float, align 4
@@ -135,7 +135,7 @@ eh.resume:                                        ; %catch.dispatch3
 ; CHECK: }
 ; CHECK: }
 }
 }
 
 
-; CHECK: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) {
+; CHECK: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*)
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   [[RECOVER_I:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0)
 ; CHECK:   [[RECOVER_I:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0)
 ; CHECK:   [[I_PTR:\%.+]] = bitcast i8* [[RECOVER_I]] to i32*
 ; CHECK:   [[I_PTR:\%.+]] = bitcast i8* [[RECOVER_I]] to i32*
@@ -158,7 +158,7 @@ eh.resume:                                        ; %catch.dispatch3
 ;
 ;
 ; CHECK: }
 ; CHECK: }
 
 
-; CHECK: define internal i8* @"\01?test@@YAXXZ.catch1"(i8*, i8*) {
+; CHECK: define internal i8* @"\01?test@@YAXXZ.catch1"(i8*, i8*)
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   [[RECOVER_F1:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1)
 ; CHECK:   [[RECOVER_F1:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1)
 ; CHECK:   [[F_PTR1:\%.+]] = bitcast i8* [[RECOVER_F1]] to float*
 ; CHECK:   [[F_PTR1:\%.+]] = bitcast i8* [[RECOVER_F1]] to float*

+ 5 - 5
test/CodeGen/WinEH/cppeh-nested-2.ll

@@ -38,7 +38,7 @@ target triple = "x86_64-pc-windows-msvc"
 @_ZTIi = external constant i8*
 @_ZTIi = external constant i8*
 
 
 ; The function entry should be rewritten like this.
 ; The function entry should be rewritten like this.
-; CHECK: define void @_Z4testv() #0 {
+; CHECK: define void @_Z4testv()
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   %outer = alloca %class.Outer, align 1
 ; CHECK:   %outer = alloca %class.Outer, align 1
 ; CHECK:   %inner = alloca %class.Inner, align 1
 ; CHECK:   %inner = alloca %class.Inner, align 1
@@ -241,7 +241,7 @@ eh.resume:                                        ; preds = %catch.dispatch11
 }
 }
 
 
 ; This catch handler should be outlined.
 ; This catch handler should be outlined.
-; CHECK: define internal i8* @_Z4testv.catch(i8*, i8*) {
+; CHECK: define internal i8* @_Z4testv.catch(i8*, i8*)
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   [[RECOVER_F:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 0)
 ; CHECK:   [[RECOVER_F:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 0)
 ; CHECK:   [[F_PTR:\%.+]] = bitcast i8* [[RECOVER_F]] to float*
 ; CHECK:   [[F_PTR:\%.+]] = bitcast i8* [[RECOVER_F]] to float*
@@ -251,7 +251,7 @@ eh.resume:                                        ; preds = %catch.dispatch11
 ; CHECK: }
 ; CHECK: }
 
 
 ; This catch handler should be outlined.
 ; This catch handler should be outlined.
-; CHECK: define internal i8* @_Z4testv.catch1(i8*, i8*) {
+; CHECK: define internal i8* @_Z4testv.catch1(i8*, i8*)
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   [[RECOVER_I:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 1)
 ; CHECK:   [[RECOVER_I:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 1)
 ; CHECK:   [[I_PTR:\%.+]] = bitcast i8* [[RECOVER_I]] to i32*
 ; CHECK:   [[I_PTR:\%.+]] = bitcast i8* [[RECOVER_I]] to i32*
@@ -268,7 +268,7 @@ eh.resume:                                        ; preds = %catch.dispatch11
 ; CHECK: }
 ; CHECK: }
 
 
 ; This cleanup handler should be outlined.
 ; This cleanup handler should be outlined.
-; CHECK: define internal void @_Z4testv.cleanup(i8*, i8*) {
+; CHECK: define internal void @_Z4testv.cleanup(i8*, i8*)
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   [[RECOVER_OUTER:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 2)
 ; CHECK:   [[RECOVER_OUTER:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 2)
 ; CHECK:   [[OUTER_PTR:\%.+]] = bitcast i8* [[RECOVER_OUTER]] to %class.Outer*
 ; CHECK:   [[OUTER_PTR:\%.+]] = bitcast i8* [[RECOVER_OUTER]] to %class.Outer*
@@ -277,7 +277,7 @@ eh.resume:                                        ; preds = %catch.dispatch11
 ; CHECK: }
 ; CHECK: }
 
 
 ; This cleanup handler should be outlined.
 ; This cleanup handler should be outlined.
-; CHECK: define internal void @_Z4testv.cleanup2(i8*, i8*) {
+; CHECK: define internal void @_Z4testv.cleanup2(i8*, i8*)
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   [[RECOVER_INNER:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 3)
 ; CHECK:   [[RECOVER_INNER:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @_Z4testv to i8*), i8* %1, i32 3)
 ; CHECK:   [[INNER_PTR:\%.+]] = bitcast i8* [[RECOVER_INNER]] to %class.Inner*
 ; CHECK:   [[INNER_PTR:\%.+]] = bitcast i8* [[RECOVER_INNER]] to %class.Inner*

+ 4 - 4
test/CodeGen/WinEH/cppeh-nested-3.ll

@@ -37,7 +37,7 @@ $"\01??_R0H@8" = comdat any
 @"\01??_R0M@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".M\00" }, comdat
 @"\01??_R0M@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".M\00" }, comdat
 @"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
 @"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
 
 
-; CHECK: define void @"\01?test@@YAXXZ"() #0 {
+; CHECK: define void @"\01?test@@YAXXZ"()
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   %i = alloca i32, align 4
 ; CHECK:   %i = alloca i32, align 4
 ; ------------================= FAIL here =================------------
 ; ------------================= FAIL here =================------------
@@ -182,7 +182,7 @@ eh.resume:                                        ; preds = %lpad16, %catch.disp
 ; CHECK: }
 ; CHECK: }
 }
 }
 
 
-; CHECK: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) {
+; CHECK: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*)
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   [[RECOVER_I:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0)
 ; CHECK:   [[RECOVER_I:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0)
 ; CHECK:   [[I_PTR:\%.+]] = bitcast i8* [[RECOVER_I]] to i32*
 ; CHECK:   [[I_PTR:\%.+]] = bitcast i8* [[RECOVER_I]] to i32*
@@ -220,7 +220,7 @@ eh.resume:                                        ; preds = %lpad16, %catch.disp
 ;
 ;
 ; CHECK: }
 ; CHECK: }
 
 
-; CHECK: define internal i8* @"\01?test@@YAXXZ.catch1"(i8*, i8*) {
+; CHECK: define internal i8* @"\01?test@@YAXXZ.catch1"(i8*, i8*)
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   [[RECOVER_F1:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1)
 ; CHECK:   [[RECOVER_F1:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1)
 ; CHECK:   [[F_PTR1:\%.+]] = bitcast i8* [[RECOVER_F1]] to float*
 ; CHECK:   [[F_PTR1:\%.+]] = bitcast i8* [[RECOVER_F1]] to float*
@@ -229,7 +229,7 @@ eh.resume:                                        ; preds = %lpad16, %catch.disp
 ; CHECK:   ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont19)
 ; CHECK:   ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont19)
 ; CHECK: }
 ; CHECK: }
 
 
-; CHECK: define internal i8* @"\01?test@@YAXXZ.catch2"(i8*, i8*) {
+; CHECK: define internal i8* @"\01?test@@YAXXZ.catch2"(i8*, i8*)
 ; CHECK: entry:
 ; CHECK: entry:
 ; ------------================= FAIL here =================------------
 ; ------------================= FAIL here =================------------
 ; SHOULD-CHECK:   [[J_PTR1:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 2)
 ; SHOULD-CHECK:   [[J_PTR1:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 2)

+ 2 - 2
test/CodeGen/WinEH/cppeh-nonalloca-frame-values.ll

@@ -51,7 +51,7 @@ $"\01??_R0H@8" = comdat any
 @"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
 @"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
 
 
 ; The function entry should be rewritten like this.
 ; The function entry should be rewritten like this.
-; CHECK: define void @"\01?test@@YAXXZ"() #0 {
+; CHECK: define void @"\01?test@@YAXXZ"()
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   [[NUMEXCEPTIONS_REGMEM:\%.+]] = alloca i32
 ; CHECK:   [[NUMEXCEPTIONS_REGMEM:\%.+]] = alloca i32
 ; CHECK:   [[I_REGMEM:\%.+]] = alloca i32
 ; CHECK:   [[I_REGMEM:\%.+]] = alloca i32
@@ -190,7 +190,7 @@ eh.resume:                                        ; preds = %lpad
 }
 }
 
 
 ; The following catch handler should be outlined.
 ; The following catch handler should be outlined.
-; CHECK: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) {
+; CHECK: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*)
 ; CHECK: entry:
 ; CHECK: entry:
 ; CHECK:   [[RECOVER_E:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0)
 ; CHECK:   [[RECOVER_E:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0)
 ; CHECK:   [[E_PTR:\%.+]] = bitcast i8* [[RECOVER_E]] to i32*
 ; CHECK:   [[E_PTR:\%.+]] = bitcast i8* [[RECOVER_E]] to i32*