[llvm] r249078 - [WinEH] Emit __C_specific_handler tables for the new IR

Reid Kleckner via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 1 14:38:25 PDT 2015


Author: rnk
Date: Thu Oct  1 16:38:24 2015
New Revision: 249078

URL: http://llvm.org/viewvc/llvm-project?rev=249078&view=rev
Log:
[WinEH] Emit __C_specific_handler tables for the new IR

We emit denormalized tables, where every range of invokes in the same
state gets a complete list of EH action entries. This is significantly
simpler than trying to infer the correct nested scoping structure from
the MI. Fortunately, for SEH, the nesting structure is really just a
size optimization.

With this, some basic __try / __except examples work.

Added:
    llvm/trunk/test/CodeGen/X86/seh-catchpad.ll
Modified:
    llvm/trunk/include/llvm/CodeGen/WinEHFuncInfo.h
    llvm/trunk/lib/CodeGen/AsmPrinter/EHStreamer.h
    llvm/trunk/lib/CodeGen/AsmPrinter/WinException.cpp
    llvm/trunk/lib/CodeGen/WinEHPrepare.cpp
    llvm/trunk/lib/Target/X86/X86FrameLowering.cpp

Modified: llvm/trunk/include/llvm/CodeGen/WinEHFuncInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/WinEHFuncInfo.h?rev=249078&r1=249077&r2=249078&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/WinEHFuncInfo.h (original)
+++ llvm/trunk/include/llvm/CodeGen/WinEHFuncInfo.h Thu Oct  1 16:38:24 2015
@@ -131,6 +131,8 @@ struct SEHUnwindMapEntry {
   /// this state. This indexes into SEHUnwindMap.
   int ToState = -1;
 
+  bool IsFinally = false;
+
   /// Holds the filter expression function.
   const Function *Filter = nullptr;
 

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/EHStreamer.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/EHStreamer.h?rev=249078&r1=249077&r2=249078&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/EHStreamer.h (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/EHStreamer.h Thu Oct  1 16:38:24 2015
@@ -76,10 +76,6 @@ protected:
                                SmallVectorImpl<ActionEntry> &Actions,
                                SmallVectorImpl<unsigned> &FirstActions);
 
-  /// Return `true' if this is a call to a function marked `nounwind'. Return
-  /// `false' otherwise.
-  bool callToNoUnwindFunction(const MachineInstr *MI);
-
   void computePadMap(const SmallVectorImpl<const LandingPadInfo *> &LandingPads,
                      RangeMapType &PadMap);
 
@@ -131,6 +127,10 @@ public:
   void setSymbolSize(const MCSymbol *Sym, uint64_t Size) override {}
   void beginInstruction(const MachineInstr *MI) override {}
   void endInstruction() override {}
+
+  /// Return `true' if this is a call to a function marked `nounwind'. Return
+  /// `false' otherwise.
+  static bool callToNoUnwindFunction(const MachineInstr *MI);
 };
 }
 

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/WinException.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/WinException.cpp?rev=249078&r1=249077&r2=249078&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/WinException.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/WinException.cpp Thu Oct  1 16:38:24 2015
@@ -121,6 +121,10 @@ void WinException::endFunction(const Mac
 
   endFunclet();
 
+  // endFunclet will emit the necessary .xdata tables for x64 SEH.
+  if (Per == EHPersonality::MSVC_Win64SEH && MMI->hasEHFunclets())
+    return;
+
   if (shouldEmitPersonality || shouldEmitLSDA) {
     Asm->OutStreamer->PushSection();
 
@@ -237,14 +241,19 @@ void WinException::endFunclet() {
     // Emit an UNWIND_INFO struct describing the prologue.
     Asm->OutStreamer->EmitWinEHHandlerData();
 
-    // If this is a C++ catch funclet (or the parent function),
-    // emit a reference to the LSDA for the parent function.
     if (Per == EHPersonality::MSVC_CXX && shouldEmitPersonality &&
         !CurrentFuncletEntry->isCleanupFuncletEntry()) {
+      // If this is a C++ catch funclet (or the parent function),
+      // emit a reference to the LSDA for the parent function.
       StringRef FuncLinkageName = GlobalValue::getRealLinkageName(F->getName());
       MCSymbol *FuncInfoXData = Asm->OutContext.getOrCreateSymbol(
           Twine("$cppxdata$", FuncLinkageName));
       Asm->OutStreamer->EmitValue(create32bitRef(FuncInfoXData), 4);
+    } else if (Per == EHPersonality::MSVC_Win64SEH && MMI->hasEHFunclets() &&
+               !CurrentFuncletEntry->isEHFuncletEntry()) {
+      // If this is the parent function in Win64 SEH, emit the LSDA immediately
+      // following .seh_handlerdata.
+      emitCSpecificHandlerTable(Asm->MF);
     }
 
     // Switch back to the previous section now that we are done writing to
@@ -283,6 +292,96 @@ const MCExpr *WinException::getLabelPlus
                                  Asm->OutContext);
 }
 
+/// Information describing an invoke range.
+struct InvokeRange {
+  MCSymbol *BeginLabel = nullptr;
+  MCSymbol *EndLabel = nullptr;
+  int State = -1;
+
+  /// If we saw a potentially throwing call between this range and the last
+  /// range.
+  bool SawPotentiallyThrowing = false;
+};
+
+/// Iterator over the begin/end label pairs of invokes within a basic block.
+class InvokeLabelIterator {
+public:
+  InvokeLabelIterator(WinEHFuncInfo &EHInfo,
+                      MachineBasicBlock::const_iterator MBBI,
+                      MachineBasicBlock::const_iterator MBBIEnd)
+      : EHInfo(EHInfo), MBBI(MBBI), MBBIEnd(MBBIEnd) {
+    scan();
+  }
+
+  // Iterator methods.
+  bool operator==(const InvokeLabelIterator &o) const { return MBBI == o.MBBI; }
+  bool operator!=(const InvokeLabelIterator &o) const { return MBBI != o.MBBI; }
+  InvokeRange &operator*() { return CurRange; }
+  InvokeRange *operator->() { return &CurRange; }
+  InvokeLabelIterator &operator++() { return scan(); }
+
+private:
+  // Scan forward to find the next invoke range, or hit the end iterator.
+  InvokeLabelIterator &scan();
+
+  WinEHFuncInfo &EHInfo;
+  MachineBasicBlock::const_iterator MBBI;
+  MachineBasicBlock::const_iterator MBBIEnd;
+  InvokeRange CurRange;
+};
+
+/// Invoke label range iteration logic. Increment MBBI until we find the next
+/// EH_LABEL pair, and then update MBBI to point after the end label.
+InvokeLabelIterator &InvokeLabelIterator::scan() {
+  // Reset our state.
+  CurRange = InvokeRange{};
+
+  for (const MachineInstr &MI : make_range(MBBI, MBBIEnd)) {
+    // Remember if we had to cross a potentially throwing call instruction that
+    // must unwind to caller.
+    if (MI.isCall()) {
+      CurRange.SawPotentiallyThrowing |=
+          !EHStreamer::callToNoUnwindFunction(&MI);
+      continue;
+    }
+    // Find the next EH_LABEL instruction.
+    if (!MI.isEHLabel())
+      continue;
+
+    // If this is a begin label, break out with the state and end label.
+    // Otherwise this is probably a CFI EH_LABEL that we should continue past.
+    MCSymbol *Label = MI.getOperand(0).getMCSymbol();
+    auto StateAndEnd = EHInfo.InvokeToStateMap.find(Label);
+    if (StateAndEnd == EHInfo.InvokeToStateMap.end())
+      continue;
+    MBBI = MachineBasicBlock::const_iterator(&MI);
+    CurRange.BeginLabel = Label;
+    CurRange.EndLabel = StateAndEnd->second.second;
+    CurRange.State = StateAndEnd->second.first;
+    break;
+  }
+
+  // If we didn't find a begin label, we are done, return the end iterator.
+  if (!CurRange.BeginLabel) {
+    MBBI = MBBIEnd;
+    return *this;
+  }
+
+  // If this is a begin label, update MBBI to point past the end label.
+  for (; MBBI != MBBIEnd; ++MBBI)
+    if (MBBI->isEHLabel() &&
+        MBBI->getOperand(0).getMCSymbol() == CurRange.EndLabel)
+      break;
+  return *this;
+}
+
+/// Utility for making a range for all the invoke ranges.
+static iterator_range<InvokeLabelIterator>
+invoke_ranges(WinEHFuncInfo &EHInfo, const MachineBasicBlock &MBB) {
+  return make_range(InvokeLabelIterator(EHInfo, MBB.begin(), MBB.end()),
+                    InvokeLabelIterator(EHInfo, MBB.end(), MBB.end()));
+}
+
 /// Emit the language-specific data that __C_specific_handler expects.  This
 /// handler lives in the x64 Microsoft C runtime and allows catching or cleaning
 /// up after faults with __try, __except, and __finally.  The typeinfo values
@@ -312,11 +411,86 @@ const MCExpr *WinException::getLabelPlus
 ///     } Entries[NumEntries];
 ///   };
 void WinException::emitCSpecificHandlerTable(const MachineFunction *MF) {
-  const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
+  auto &OS = *Asm->OutStreamer;
+  MCContext &Ctx = Asm->OutContext;
 
   WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(MF->getFunction());
-  if (!FuncInfo.SEHUnwindMap.empty())
-    report_fatal_error("x64 SEH tables not yet implemented");
+  if (!FuncInfo.SEHUnwindMap.empty()) {
+    // Remember what state we were in the last time we found a begin try label.
+    // This allows us to coalesce many nearby invokes with the same state into
+    // one entry.
+    int LastEHState = -1;
+    MCSymbol *LastBeginLabel = nullptr;
+    MCSymbol *LastEndLabel = nullptr;
+
+    // Use the assembler to compute the number of table entries through label
+    // difference and division.
+    MCSymbol *TableBegin = Ctx.createTempSymbol("lsda_begin");
+    MCSymbol *TableEnd = Ctx.createTempSymbol("lsda_end");
+    const MCExpr *LabelDiff =
+        MCBinaryExpr::createSub(MCSymbolRefExpr::create(TableEnd, Ctx),
+                                MCSymbolRefExpr::create(TableBegin, Ctx), Ctx);
+    const MCExpr *EntrySize = MCConstantExpr::create(16, Ctx);
+    const MCExpr *EntryCount =
+        MCBinaryExpr::createDiv(LabelDiff, EntrySize, Ctx);
+    OS.EmitValue(EntryCount, 4);
+
+    OS.EmitLabel(TableBegin);
+
+    // Iterate over all the invoke try ranges. Unlike MSVC, LLVM currently only
+    // models exceptions from invokes. LLVM also allows arbitrary reordering of
+    // the code, so our tables end up looking a bit different. Rather than
+    // trying to match MSVC's tables exactly, we emit a denormalized table.  For
+    // each range of invokes in the same state, we emit table entries for all
+    // the actions that would be taken in that state. This means our tables are
+    // slightly bigger, which is OK.
+    for (const auto &MBB : *MF) {
+      for (InvokeRange &I : invoke_ranges(FuncInfo, MBB)) {
+        // If this invoke is in the same state as the last invoke and there were
+        // no non-throwing calls between it, extend the range to include both
+        // and continue.
+        if (!I.SawPotentiallyThrowing && I.State == LastEHState) {
+          LastEndLabel = I.EndLabel;
+          continue;
+        }
+
+        // If this invoke ends a previous one, emit all the actions for this
+        // state.
+        if (LastEHState != -1) {
+          assert(LastBeginLabel && LastEndLabel);
+          for (int State = LastEHState; State != -1;) {
+            SEHUnwindMapEntry &UME = FuncInfo.SEHUnwindMap[State];
+            const MCExpr *FilterOrFinally;
+            const MCExpr *ExceptOrNull;
+            auto *Handler = UME.Handler.get<MachineBasicBlock *>();
+            if (UME.IsFinally) {
+              FilterOrFinally = create32bitRef(Handler->getSymbol());
+              ExceptOrNull = MCConstantExpr::create(0, Ctx);
+            } else {
+              // For an except, the filter can be 1 (catch-all) or a function
+              // label.
+              FilterOrFinally = UME.Filter ? create32bitRef(UME.Filter)
+                                           : MCConstantExpr::create(1, Ctx);
+              ExceptOrNull = create32bitRef(Handler->getSymbol());
+            }
+
+            OS.EmitValue(getLabelPlusOne(LastBeginLabel), 4);
+            OS.EmitValue(getLabelPlusOne(LastEndLabel), 4);
+            OS.EmitValue(FilterOrFinally, 4);
+            OS.EmitValue(ExceptOrNull, 4);
+
+            State = UME.ToState;
+          }
+        }
+
+        LastBeginLabel = I.BeginLabel;
+        LastEndLabel = I.EndLabel;
+        LastEHState = I.State;
+      }
+    }
+    OS.EmitLabel(TableEnd);
+    return;
+  }
 
   // Simplifying assumptions for first implementation:
   // - Cleanups are not implemented.
@@ -324,6 +498,7 @@ void WinException::emitCSpecificHandlerT
 
   // The Itanium LSDA table sorts similar landing pads together to simplify the
   // actions table, but we don't need that.
+  const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
   SmallVector<const LandingPadInfo *, 64> LandingPads;
   LandingPads.reserve(PadInfos.size());
   for (const auto &LP : PadInfos)
@@ -346,7 +521,7 @@ void WinException::emitCSpecificHandlerT
       continue; // Ignore gaps.
     NumEntries += CSE.LPad->SEHHandlers.size();
   }
-  Asm->OutStreamer->EmitIntValue(NumEntries, 4);
+  OS.EmitIntValue(NumEntries, 4);
 
   // If there are no actions, we don't need to iterate again.
   if (NumEntries == 0)
@@ -377,25 +552,25 @@ void WinException::emitCSpecificHandlerT
 
     // Emit an entry for each action.
     for (SEHHandler Handler : LPad->SEHHandlers) {
-      Asm->OutStreamer->EmitValue(Begin, 4);
-      Asm->OutStreamer->EmitValue(End, 4);
+      OS.EmitValue(Begin, 4);
+      OS.EmitValue(End, 4);
 
       // Emit the filter or finally function pointer, if present. Otherwise,
       // emit '1' to indicate a catch-all.
       const Function *F = Handler.FilterOrFinally;
       if (F)
-        Asm->OutStreamer->EmitValue(create32bitRef(Asm->getSymbol(F)), 4);
+        OS.EmitValue(create32bitRef(Asm->getSymbol(F)), 4);
       else
-        Asm->OutStreamer->EmitIntValue(1, 4);
+        OS.EmitIntValue(1, 4);
 
       // Emit the recovery address, if present. Otherwise, this must be a
       // finally.
       const BlockAddress *BA = Handler.RecoverBA;
       if (BA)
-        Asm->OutStreamer->EmitValue(
+        OS.EmitValue(
             create32bitRef(Asm->GetBlockAddressSymbol(BA)), 4);
       else
-        Asm->OutStreamer->EmitIntValue(0, 4);
+        OS.EmitIntValue(0, 4);
     }
   }
 }
@@ -583,10 +758,6 @@ void WinException::emitCXXFrameHandler3T
 void WinException::computeIP2StateTable(
     const MachineFunction *MF, WinEHFuncInfo &FuncInfo,
     SmallVectorImpl<std::pair<const MCExpr *, int>> &IPToStateTable) {
-  // 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 = true;
-
   // Remember what state we were in the last time we found a begin try label.
   // This allows us to coalesce many nearby invokes with the same state into one
   // entry.
@@ -602,49 +773,23 @@ void WinException::computeIP2StateTable(
   for (const auto &MBB : *MF) {
     // FIXME: Do we need to emit entries for funclet base states?
 
-    for (const auto &MI : MBB) {
-      // Find all the EH_LABEL instructions, tracking if we've crossed a
-      // potentially throwing call since the last label.
-      if (!MI.isEHLabel()) {
-        if (MI.isCall())
-          SawPotentiallyThrowing |= !callToNoUnwindFunction(&MI);
-        continue;
-      }
-
-      // If this was an end label, return SawPotentiallyThrowing to the start
-      // state and keep going. Otherwise, we will consider the call between the
-      // begin/end labels to be a potentially throwing call and generate extra
-      // table entries.
-      MCSymbol *Label = MI.getOperand(0).getMCSymbol();
-      if (Label == LastEndLabel)
-        SawPotentiallyThrowing = false;
-
-      // Check if this was a begin label. Otherwise, it must be an end label or
-      // some random label, and we should continue.
-      auto StateAndEnd = FuncInfo.InvokeToStateMap.find(Label);
-      if (StateAndEnd == FuncInfo.InvokeToStateMap.end())
-        continue;
-
-      // Extract the state and end label.
-      int State;
-      MCSymbol *EndLabel;
-      std::tie(State, EndLabel) = StateAndEnd->second;
-
+    for (InvokeRange &I : invoke_ranges(FuncInfo, MBB)) {
+      assert(I.BeginLabel && I.EndLabel);
       // If there was a potentially throwing call between this begin label and
       // the last end label, we need an extra base state entry to indicate that
       // those calls unwind directly to the caller.
-      if (SawPotentiallyThrowing && LastEHState != -1) {
+      if (I.SawPotentiallyThrowing && LastEHState != -1) {
         IPToStateTable.push_back(
             std::make_pair(getLabelPlusOne(LastEndLabel), -1));
-        SawPotentiallyThrowing = false;
         LastEHState = -1;
       }
 
       // Emit an entry indicating that PCs after 'Label' have this EH state.
-      if (State != LastEHState)
-        IPToStateTable.push_back(std::make_pair(create32bitRef(Label), State));
-      LastEHState = State;
-      LastEndLabel = EndLabel;
+      if (I.State != LastEHState)
+        IPToStateTable.push_back(
+            std::make_pair(create32bitRef(I.BeginLabel), I.State));
+      LastEHState = I.State;
+      LastEndLabel = I.EndLabel;
     }
   }
 

Modified: llvm/trunk/lib/CodeGen/WinEHPrepare.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/WinEHPrepare.cpp?rev=249078&r1=249077&r2=249078&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/WinEHPrepare.cpp (original)
+++ llvm/trunk/lib/CodeGen/WinEHPrepare.cpp Thu Oct  1 16:38:24 2015
@@ -2724,16 +2724,28 @@ static void calculateExplicitCXXStateNum
   }
 }
 
-static int addSEHHandler(WinEHFuncInfo &FuncInfo, int ParentState,
-                         const Function *Filter, const BasicBlock *Handler) {
+static int addSEHExcept(WinEHFuncInfo &FuncInfo, int ParentState,
+                        const Function *Filter, const BasicBlock *Handler) {
   SEHUnwindMapEntry Entry;
   Entry.ToState = ParentState;
+  Entry.IsFinally = false;
   Entry.Filter = Filter;
   Entry.Handler = Handler;
   FuncInfo.SEHUnwindMap.push_back(Entry);
   return FuncInfo.SEHUnwindMap.size() - 1;
 }
 
+static int addSEHFinally(WinEHFuncInfo &FuncInfo, int ParentState,
+                         const BasicBlock *Handler) {
+  SEHUnwindMapEntry Entry;
+  Entry.ToState = ParentState;
+  Entry.IsFinally = true;
+  Entry.Filter = nullptr;
+  Entry.Handler = Handler;
+  FuncInfo.SEHUnwindMap.push_back(Entry);
+  return FuncInfo.SEHUnwindMap.size() - 1;
+}
+
 static void calculateExplicitSEHStateNumbers(WinEHFuncInfo &FuncInfo,
                                              const BasicBlock &BB,
                                              int ParentState) {
@@ -2753,10 +2765,13 @@ static void calculateExplicitSEHStateNum
            "SEH doesn't have multiple handlers per __try");
     const CatchPadInst *CPI = Handlers.front();
     const BasicBlock *CatchPadBB = CPI->getParent();
-    const Function *Filter =
-        cast<Function>(CPI->getArgOperand(0)->stripPointerCasts());
+    const Constant *FilterOrNull =
+        cast<Constant>(CPI->getArgOperand(0)->stripPointerCasts());
+    const Function *Filter = dyn_cast<Function>(FilterOrNull);
+    assert((Filter || FilterOrNull->isNullValue()) &&
+           "unexpected filter value");
     int TryState =
-        addSEHHandler(FuncInfo, ParentState, Filter, CPI->getNormalDest());
+        addSEHExcept(FuncInfo, ParentState, Filter, CPI->getNormalDest());
 
     // Everything in the __try block uses TryState as its parent state.
     FuncInfo.EHPadStateMap[CPI] = TryState;
@@ -2775,8 +2790,7 @@ static void calculateExplicitSEHStateNum
       if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
         calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, ParentState);
   } else if (isa<CleanupPadInst>(FirstNonPHI)) {
-    int CleanupState =
-        addSEHHandler(FuncInfo, ParentState, /*Filter=*/nullptr, &BB);
+    int CleanupState = addSEHFinally(FuncInfo, ParentState, &BB);
     FuncInfo.EHPadStateMap[FirstNonPHI] = CleanupState;
     DEBUG(dbgs() << "Assigning state #" << CleanupState << " to BB "
                  << BB.getName() << '\n');

Modified: llvm/trunk/lib/Target/X86/X86FrameLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86FrameLowering.cpp?rev=249078&r1=249077&r2=249078&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86FrameLowering.cpp (original)
+++ llvm/trunk/lib/Target/X86/X86FrameLowering.cpp Thu Oct  1 16:38:24 2015
@@ -1489,10 +1489,21 @@ bool X86FrameLowering::restoreCalleeSave
   if (CSI.empty())
     return false;
 
-  // Don't restore CSRs in 32-bit EH funclets. Matches
-  // spillCalleeSavedRegisters.
-  if (isFuncletReturnInstr(MI) && STI.is32Bit() && STI.isOSWindows())
-    return true;
+  if (isFuncletReturnInstr(MI) && STI.isOSWindows()) {
+    // Don't restore CSRs in 32-bit EH funclets. Matches
+    // spillCalleeSavedRegisters.
+    if (STI.is32Bit())
+      return true;
+    // Don't restore CSRs before an SEH catchret. SEH except blocks do not form
+    // funclets. emitEpilogue transforms these to normal jumps.
+    if (MI->getOpcode() == X86::CATCHRET) {
+      const Function *Func = MBB.getParent()->getFunction();
+      bool IsSEH = isAsynchronousEHPersonality(
+          classifyEHPersonality(Func->getPersonalityFn()));
+      if (IsSEH)
+        return true;
+    }
+  }
 
   DebugLoc DL = MBB.findDebugLoc(MI);
 

Added: llvm/trunk/test/CodeGen/X86/seh-catchpad.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/seh-catchpad.ll?rev=249078&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/X86/seh-catchpad.ll (added)
+++ llvm/trunk/test/CodeGen/X86/seh-catchpad.ll Thu Oct  1 16:38:24 2015
@@ -0,0 +1,202 @@
+; RUN: llc < %s | FileCheck %s
+
+; Based on the source:
+; extern "C" int puts(const char *);
+; extern "C" int printf(const char *, ...);
+; extern "C" int do_div(int a, int b) { return a / b; }
+; extern "C" int filt();
+; int main() {
+;   __try {
+;     __try {
+;       do_div(1, 0);
+;     } __except (1) {
+;       __try {
+;         do_div(1, 0);
+;       } __finally {
+;         puts("finally");
+;       }
+;     }
+;   } __except (filt()) {
+;     puts("caught");
+;   }
+;   return 0;
+; }
+
+; ModuleID = 't.cpp'
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+$"\01??_C at _07MKBLAIAL@finally?$AA@" = comdat any
+
+$"\01??_C at _06IBDBCMGJ@caught?$AA@" = comdat any
+
+@"\01??_C at _07MKBLAIAL@finally?$AA@" = linkonce_odr unnamed_addr constant [8 x i8] c"finally\00", comdat, align 1
+@"\01??_C at _06IBDBCMGJ@caught?$AA@" = linkonce_odr unnamed_addr constant [7 x i8] c"caught\00", comdat, align 1
+
+; Function Attrs: nounwind readnone
+define i32 @do_div(i32 %a, i32 %b) #0 {
+entry:
+  %div = sdiv i32 %a, %b
+  ret i32 %div
+}
+
+define i32 @main() #1 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) {
+entry:
+  %call = invoke i32 @do_div(i32 1, i32 0) #4
+          to label %__try.cont.12 unwind label %catch.dispatch
+
+catch.dispatch:                                   ; preds = %entry
+  %0 = catchpad [i8* null]
+          to label %__except unwind label %catchendblock
+
+__except:                                         ; preds = %catch.dispatch
+  catchret %0 to label %__except.2
+
+__except.2:                                       ; preds = %__except
+  %call4 = invoke i32 @do_div(i32 1, i32 0) #4
+          to label %invoke.cont.3 unwind label %ehcleanup
+
+invoke.cont.3:                                    ; preds = %__except.2
+  invoke fastcc void @"\01?fin$0 at 0@main@@"() #4
+          to label %__try.cont.12 unwind label %catch.dispatch.7
+
+catchendblock:                                    ; preds = %catch.dispatch
+  catchendpad unwind label %catch.dispatch.7
+
+ehcleanup:                                        ; preds = %__except.2
+  %1 = cleanuppad []
+  invoke fastcc void @"\01?fin$0 at 0@main@@"() #4
+          to label %invoke.cont.6 unwind label %ehcleanup.end
+
+invoke.cont.6:                                    ; preds = %ehcleanup
+  cleanupret %1 unwind label %catch.dispatch.7
+
+catch.dispatch.7:                                 ; preds = %invoke.cont.3, %invoke.cont.6, %ehcleanup.end, %catchendblock
+  %2 = catchpad [i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0 at 0@main@@" to i8*)]
+          to label %__except.ret unwind label %catchendblock.8
+
+__except.ret:                                     ; preds = %catch.dispatch.7
+  catchret %2 to label %__except.9
+
+__except.9:                                       ; preds = %__except.ret
+  %call11 = tail call i32 @puts(i8* nonnull getelementptr inbounds ([7 x i8], [7 x i8]* @"\01??_C at _06IBDBCMGJ@caught?$AA@", i64 0, i64 0))
+  br label %__try.cont.12
+
+__try.cont.12:                                    ; preds = %invoke.cont.3, %entry, %__except.9
+  ret i32 0
+
+catchendblock.8:                                  ; preds = %catch.dispatch.7
+  catchendpad unwind to caller
+
+ehcleanup.end:                                    ; preds = %ehcleanup
+  cleanupendpad %1 unwind label %catch.dispatch.7
+}
+
+; CHECK: main:                                   # @main
+; CHECK: .seh_proc main
+; CHECK:         .seh_handler __C_specific_handler, @unwind, @except
+; CHECK:         pushq   %rbp
+; CHECK:         .seh_pushreg 5
+; CHECK:         subq    $48, %rsp
+; CHECK:         .seh_stackalloc 48
+; CHECK:         leaq    48(%rsp), %rbp
+; CHECK:         .seh_setframe 5, 48
+; CHECK:         .seh_endprologue
+; CHECK: .Ltmp0:
+; CHECK:         movl    $1, %ecx
+; CHECK:         xorl    %edx, %edx
+; CHECK:         callq   do_div
+; CHECK: .Ltmp1:
+; CHECK: .LBB1_[[epilogue:[0-9]+]]:                                # %__try.cont.12
+; CHECK:         xorl    %eax, %eax
+; CHECK:         addq    $48, %rsp
+; CHECK:         popq    %rbp
+; CHECK:         retq
+; CHECK: .LBB1_[[except1bb:[0-9]+]]:                                # %__except
+; CHECK: .Ltmp2:
+; CHECK:         movl    $1, %ecx
+; CHECK:         xorl    %edx, %edx
+; CHECK:         callq   do_div
+; CHECK: .Ltmp3:
+; CHECK:         callq   "?fin$0 at 0@main@@"
+; CHECK:         jmp     .LBB1_[[epilogue]]
+; CHECK: .LBB1_[[except2bb:[0-9]+]]:                                # %__except.ret
+; CHECK:         leaq    "??_C at _06IBDBCMGJ@caught?$AA@"(%rip), %rcx
+; CHECK:         callq   puts
+; CHECK:         jmp     .LBB1_[[epilogue]]
+
+; CHECK:         .seh_handlerdata
+; CHECK-NEXT:         .long   (.Ltmp14-.Ltmp13)/16
+; CHECK-NEXT: .Ltmp13:
+; CHECK-NEXT:         .long   .Ltmp0 at IMGREL
+; CHECK-NEXT:         .long   .Ltmp1 at IMGREL+1
+; CHECK-NEXT:         .long   1
+; CHECK-NEXT:         .long   .LBB1_[[except1bb]]@IMGREL
+; CHECK-NEXT:         .long   .Ltmp0 at IMGREL
+; CHECK-NEXT:         .long   .Ltmp1 at IMGREL+1
+; CHECK-NEXT:         .long   "?filt$0 at 0@main@@"@IMGREL
+; CHECK-NEXT:         .long   .LBB1_[[except2bb]]@IMGREL
+; CHECK-NEXT:         .long   .Ltmp2 at IMGREL
+; CHECK-NEXT:         .long   .Ltmp3 at IMGREL+1
+; CHECK-NEXT:         .long   .LBB1_[[finbb:[0-9]+]]@IMGREL
+; CHECK-NEXT:         .long   0
+; CHECK-NEXT:         .long   .Ltmp2 at IMGREL
+; CHECK-NEXT:         .long   .Ltmp3 at IMGREL+1
+; CHECK-NEXT:         .long   "?filt$0 at 0@main@@"@IMGREL
+; CHECK-NEXT:         .long   .LBB1_6 at IMGREL
+; CHECK-NEXT: .Ltmp14:
+
+; CHECK:         .text
+; CHECK:         .seh_endproc
+
+; CHECK: "?dtor$4@?0?main at 4HA":
+; CHECK: .seh_proc "?dtor$4@?0?main at 4HA"
+; CHECK:         .seh_handler __C_specific_handler, @unwind, @except
+; CHECK: .LBB1_[[finbb]]:                                # %ehcleanup
+; CHECK:         movq    %rdx, 16(%rsp)
+; CHECK:         pushq   %rbp
+; CHECK:         .seh_pushreg 5
+; CHECK:         subq    $32, %rsp
+; CHECK:         .seh_stackalloc 32
+; CHECK:         leaq    48(%rdx), %rbp
+; CHECK:         .seh_endprologue
+; CHECK:         callq   "?fin$0 at 0@main@@"
+; CHECK:         nop
+; CHECK:         addq    $32, %rsp
+; CHECK:         popq    %rbp
+; CHECK:         retq
+; CHECK:         .seh_handlerdata
+; CHECK:         .seh_endproc
+
+define internal i32 @"\01?filt$0 at 0@main@@"(i8* nocapture readnone %exception_pointers, i8* nocapture readnone %frame_pointer) #1 {
+entry:
+  %call = tail call i32 @filt()
+  ret i32 %call
+}
+
+; CHECK: "?filt$0 at 0@main@@":                     # @"\01?filt$0 at 0@main@@"
+; CHECK: .seh_proc "?filt$0 at 0@main@@"
+; CHECK:         .seh_endprologue
+; CHECK:         rex64 jmp       filt  # TAILCALL
+; CHECK:         .seh_handlerdata
+
+declare i32 @filt() #1
+
+declare i32 @__C_specific_handler(...)
+
+; Function Attrs: noinline nounwind
+define internal fastcc void @"\01?fin$0 at 0@main@@"() #2 {
+entry:
+  %call = tail call i32 @puts(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @"\01??_C at _07MKBLAIAL@finally?$AA@", i64 0, i64 0)) #5
+  ret void
+}
+
+; Function Attrs: nounwind
+declare i32 @puts(i8* nocapture readonly) #3
+
+attributes #0 = { nounwind readnone "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { noinline nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #3 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #4 = { noinline }
+attributes #5 = { nounwind }




More information about the llvm-commits mailing list