[WinEH] Teach AsmPrinter about funclets
authorDavid Majnemer <david.majnemer@gmail.com>
Tue, 29 Sep 2015 20:12:33 +0000 (20:12 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Tue, 29 Sep 2015 20:12:33 +0000 (20:12 +0000)
Summary:
Funclets have been turned into functions by the time they hit the object
file.  Make sure that they have decent names for the symbol table and
CFI directives explaining how to reason about their prologues.

Differential Revision: http://reviews.llvm.org/D13261

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@248824 91177308-0d34-0410-b5e6-96231b3b80d8

18 files changed:
include/llvm/CodeGen/MachineBasicBlock.h
include/llvm/CodeGen/WinEHFuncInfo.h
lib/CodeGen/AsmPrinter/AsmPrinter.cpp
lib/CodeGen/AsmPrinter/AsmPrinterHandler.h
lib/CodeGen/AsmPrinter/WinException.cpp
lib/CodeGen/AsmPrinter/WinException.h
lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
lib/Target/X86/X86FrameLowering.cpp
test/CodeGen/WinEH/seh-prepared-basic.ll
test/CodeGen/X86/gcc_except_table.ll
test/CodeGen/X86/seh-catch-all.ll
test/CodeGen/X86/seh-except-finally.ll
test/CodeGen/X86/seh-finally.ll
test/CodeGen/X86/seh-safe-div.ll
test/CodeGen/X86/win-catchpad-csrs.ll
test/CodeGen/X86/win-catchpad.ll
test/CodeGen/X86/win-cleanuppad.ll
test/CodeGen/X86/win-funclet-cfi.ll [new file with mode: 0644]

index 511cc2a4500c51b8482496b84a108bd5beb0beb7..33230f92828187ecf6fbd3ef344f2ec982ad6d72 100644 (file)
@@ -114,6 +114,9 @@ protected:
   /// Indicate that this basic block is the entry block of an EH funclet.
   bool IsEHFuncletEntry = false;
 
+  /// Indicate that this basic block is the entry block of a cleanup funclet.
+  bool IsCleanupFuncletEntry = false;
+
   /// \brief since getSymbol is a relatively heavy-weight operation, the symbol
   /// is only computed once and is cached.
   mutable MCSymbol *CachedMCSymbol = nullptr;
@@ -392,6 +395,12 @@ public:
   /// Indicates if this is the entry block of an EH funclet.
   void setIsEHFuncletEntry(bool V = true) { IsEHFuncletEntry = V; }
 
+  /// Returns true if this is the entry block of a cleanup funclet.
+  bool isCleanupFuncletEntry() const { return IsCleanupFuncletEntry; }
+
+  /// Indicates if this is the entry block of a cleanup funclet.
+  void setIsCleanupFuncletEntry(bool V = true) { IsCleanupFuncletEntry = V; }
+
   // Code Layout methods.
 
   /// Move 'this' block before or after the specified block.  This only moves
index ac19ddf86bd6de961bf2cc9e16c2b556d9f96589..6563494357ee86c40bf429be6538277eb5b2e805 100644 (file)
@@ -118,7 +118,7 @@ void parseEHActions(const IntrinsicInst *II,
 // exceptions on Windows.
 
 typedef PointerUnion<const BasicBlock *, MachineBasicBlock *> MBBOrBasicBlock;
-typedef PointerUnion<const Value *, MachineBasicBlock *> ValueOrMBB;
+typedef PointerUnion<const Value *, const MachineBasicBlock *> ValueOrMBB;
 
 struct WinEHUnwindMapEntry {
   int ToState;
index 141cc0fc6e8f3e77f3ee44df8e4b42bbe11fb203..52dbd5a9df4092d8fbc1cbdf310a2eb1bc2ff273 100644 (file)
@@ -2459,6 +2459,14 @@ static void emitBasicBlockLoopComments(const MachineBasicBlock &MBB,
 /// MachineBasicBlock, an alignment (if present) and a comment describing
 /// it if appropriate.
 void AsmPrinter::EmitBasicBlockStart(const MachineBasicBlock &MBB) const {
+  // End the previous funclet and start a new one.
+  if (MBB.isEHFuncletEntry()) {
+    for (const HandlerInfo &HI : Handlers) {
+      HI.Handler->endFunclet();
+      HI.Handler->beginFunclet(MBB);
+    }
+  }
+
   // Emit an alignment directive for this block, if needed.
   if (unsigned Align = MBB.getAlignment())
     EmitAlignment(Align);
index f1efe9d835e05cc409b6091012b633166d6f2795..e59961f8576956b6638792484104d2ca74008ab5 100644 (file)
@@ -19,6 +19,7 @@
 
 namespace llvm {
 
+class MachineBasicBlock;
 class MachineFunction;
 class MachineInstr;
 class MCSymbol;
@@ -50,6 +51,11 @@ public:
   /// beginFunction at all.
   virtual void endFunction(const MachineFunction *MF) = 0;
 
+  /// \brief Emit target-specific EH funclet machinery.
+  virtual void beginFunclet(const MachineBasicBlock &MBB,
+                            MCSymbol *Sym = nullptr) {}
+  virtual void endFunclet() {}
+
   /// \brief Process beginning of an instruction.
   virtual void beginInstruction(const MachineInstr *MI) = 0;
 
index f662a1b5e70dc8fc1e7d8af9426096b32b637418..f4a279e5fe8651b5e7c08159f3bc76a5e0ccff76 100644 (file)
@@ -30,6 +30,7 @@
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSymbol.h"
 #include "llvm/MC/MCWin64EH.h"
+#include "llvm/Support/COFF.h"
 #include "llvm/Support/Dwarf.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FormattedStream.h"
@@ -98,14 +99,7 @@ void WinException::beginFunction(const MachineFunction *MF) {
     return;
   }
 
-  if (shouldEmitMoves || shouldEmitPersonality)
-    Asm->OutStreamer->EmitWinCFIStartProc(Asm->CurrentFnSym);
-
-  if (shouldEmitPersonality) {
-    const MCSymbol *PersHandlerSym =
-        TLOF.getCFIPersonalitySymbol(Per, *Asm->Mang, Asm->TM, MMI);
-    Asm->OutStreamer->EmitWinEHHandler(PersHandlerSym, true, true);
-  }
+  beginFunclet(MF->front(), Asm->CurrentFnSym);
 }
 
 /// endFunction - Gather and emit post-function exception information.
@@ -125,20 +119,16 @@ void WinException::endFunction(const MachineFunction *MF) {
   if (!isMSVCEHPersonality(Per))
     MMI->TidyLandingPads();
 
+  endFunclet();
+
   if (shouldEmitPersonality || shouldEmitLSDA) {
     Asm->OutStreamer->PushSection();
 
-    if (shouldEmitMoves || shouldEmitPersonality) {
-      // Emit an UNWIND_INFO struct describing the prologue.
-      Asm->OutStreamer->EmitWinEHHandlerData();
-    } else {
-      // Just switch sections to the right xdata section. This use of
-      // CurrentFnSym assumes that we only emit the LSDA when ending the parent
-      // function.
-      MCSection *XData = WinEH::UnwindEmitter::getXDataSection(
-          Asm->CurrentFnSym, Asm->OutContext);
-      Asm->OutStreamer->SwitchSection(XData);
-    }
+    // Just switch sections to the right xdata section. This use of CurrentFnSym
+    // assumes that we only emit the LSDA when ending the parent function.
+    MCSection *XData = WinEH::UnwindEmitter::getXDataSection(Asm->CurrentFnSym,
+                                                             Asm->OutContext);
+    Asm->OutStreamer->SwitchSection(XData);
 
     // Emit the tables appropriate to the personality function in use. If we
     // don't recognize the personality, assume it uses an Itanium-style LSDA.
@@ -153,9 +143,120 @@ void WinException::endFunction(const MachineFunction *MF) {
 
     Asm->OutStreamer->PopSection();
   }
+}
+
+/// Retreive the MCSymbol for a GlobalValue or MachineBasicBlock. GlobalValues
+/// are used in the old WinEH scheme, and they will be removed eventually.
+static MCSymbol *getMCSymbolForMBBOrGV(AsmPrinter *Asm, ValueOrMBB Handler) {
+  if (!Handler)
+    return nullptr;
+  if (Handler.is<const MachineBasicBlock *>()) {
+    auto *MBB = Handler.get<const MachineBasicBlock *>();
+    assert(MBB->isEHFuncletEntry());
+
+    // Give catches and cleanups a name based off of their parent function and
+    // their funclet entry block's number.
+    const MachineFunction *MF = MBB->getParent();
+    const Function *F = MF->getFunction();
+    StringRef FuncLinkageName = GlobalValue::getRealLinkageName(F->getName());
+    MCContext &Ctx = MF->getContext();
+    StringRef HandlerPrefix = MBB->isCleanupFuncletEntry() ? "dtor" : "catch";
+    return Ctx.getOrCreateSymbol("?" + HandlerPrefix + "$" +
+                                 Twine(MBB->getNumber()) + "@?0?" +
+                                 FuncLinkageName + "@4HA");
+  }
+  return Asm->getSymbol(cast<GlobalValue>(Handler.get<const Value *>()));
+}
+
+void WinException::beginFunclet(const MachineBasicBlock &MBB,
+                                MCSymbol *Sym) {
+  CurrentFuncletEntry = &MBB;
+
+  const Function *F = Asm->MF->getFunction();
+  // If a symbol was not provided for the funclet, invent one.
+  if (!Sym) {
+    Sym = getMCSymbolForMBBOrGV(Asm, &MBB);
+
+    // Describe our funclet symbol as a function with internal linkage.
+    Asm->OutStreamer->BeginCOFFSymbolDef(Sym);
+    Asm->OutStreamer->EmitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_STATIC);
+    Asm->OutStreamer->EmitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION
+                                         << COFF::SCT_COMPLEX_TYPE_SHIFT);
+    Asm->OutStreamer->EndCOFFSymbolDef();
+
+    // We want our funclet's entry point to be aligned such that no nops will be
+    // present after the label.
+    Asm->EmitAlignment(std::max(Asm->MF->getAlignment(), MBB.getAlignment()),
+                       F);
+
+    // Now that we've emitted the alignment directive, point at our funclet.
+    Asm->OutStreamer->EmitLabel(Sym);
+  }
 
+  // Mark 'Sym' as starting our funclet.
   if (shouldEmitMoves || shouldEmitPersonality)
+    Asm->OutStreamer->EmitWinCFIStartProc(Sym);
+
+  if (shouldEmitPersonality) {
+    const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();
+    const Function *PerFn = nullptr;
+
+    // Determine which personality routine we are using for this funclet.
+    if (F->hasPersonalityFn())
+      PerFn = dyn_cast<Function>(F->getPersonalityFn()->stripPointerCasts());
+    const MCSymbol *PersHandlerSym =
+        TLOF.getCFIPersonalitySymbol(PerFn, *Asm->Mang, Asm->TM, MMI);
+
+    // Classify the personality routine so that we may reason about it.
+    EHPersonality Per = EHPersonality::Unknown;
+    if (F->hasPersonalityFn())
+      Per = classifyEHPersonality(F->getPersonalityFn());
+
+    // Do not emit a .seh_handler directive if it is a C++ cleanup funclet.
+    if (Per != EHPersonality::MSVC_CXX ||
+        !CurrentFuncletEntry->isCleanupFuncletEntry())
+      Asm->OutStreamer->EmitWinEHHandler(PersHandlerSym, true, true);
+  }
+}
+
+void WinException::endFunclet() {
+  // No funclet to process?  Great, we have nothing to do.
+  if (!CurrentFuncletEntry)
+    return;
+
+  if (shouldEmitMoves || shouldEmitPersonality) {
+    const Function *F = Asm->MF->getFunction();
+    EHPersonality Per = EHPersonality::Unknown;
+    if (F->hasPersonalityFn())
+      Per = classifyEHPersonality(F->getPersonalityFn());
+
+    // The .seh_handlerdata directive implicitly switches section, push the
+    // current section so that we may return to it.
+    Asm->OutStreamer->PushSection();
+
+    // 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()) {
+      StringRef FuncLinkageName = GlobalValue::getRealLinkageName(F->getName());
+      MCSymbol *FuncInfoXData = Asm->OutContext.getOrCreateSymbol(
+          Twine("$cppxdata$", FuncLinkageName));
+      Asm->OutStreamer->EmitValue(create32bitRef(FuncInfoXData), 4);
+    }
+
+    // Switch back to the previous section now that we are done writing to
+    // .xdata.
+    Asm->OutStreamer->PopSection();
+
+    // Emit a .seh_endproc directive to mark the end of the function.
     Asm->OutStreamer->EmitWinCFIEndProc();
+  }
+
+  // Let's make sure we don't try to end the same funclet twice.
+  CurrentFuncletEntry = nullptr;
 }
 
 const MCExpr *WinException::create32bitRef(const MCSymbol *Value) {
@@ -299,16 +400,6 @@ void WinException::emitCSpecificHandlerTable(const MachineFunction *MF) {
   }
 }
 
-/// Retreive the MCSymbol for a GlobalValue or MachineBasicBlock. GlobalValues
-/// are used in the old WinEH scheme, and they will be removed eventually.
-static MCSymbol *getMCSymbolForMBBOrGV(AsmPrinter *Asm, ValueOrMBB Handler) {
-  if (!Handler)
-    return nullptr;
-  if (Handler.is<MachineBasicBlock *>())
-    return Handler.get<MachineBasicBlock *>()->getSymbol();
-  return Asm->getSymbol(cast<GlobalValue>(Handler.get<const Value *>()));
-}
-
 void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
   const Function *F = MF->getFunction();
   auto &OS = *Asm->OutStreamer;
@@ -323,7 +414,6 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
     // IPs to state numbers.
     FuncInfoXData =
         Asm->OutContext.getOrCreateSymbol(Twine("$cppxdata$", FuncLinkageName));
-    OS.EmitValue(create32bitRef(FuncInfoXData), 4);
     computeIP2StateTable(MF, FuncInfo, IPToStateTable);
   } else {
     FuncInfoXData = Asm->OutContext.getOrCreateLSDASymbol(FuncLinkageName);
index 37d2ab6ae4eee87f163db8dcd79a68824c62f31e..bf1724f60f7ab1d5933650e692b5968be4b13453 100644 (file)
@@ -36,6 +36,9 @@ class LLVM_LIBRARY_VISIBILITY WinException : public EHStreamer {
   /// True if this is a 64-bit target and we should use image relative offsets.
   bool useImageRel32 = false;
 
+  /// Pointer to the current funclet entry BB.
+  const MachineBasicBlock *CurrentFuncletEntry = nullptr;
+
   void emitCSpecificHandlerTable(const MachineFunction *MF);
 
   /// Emit the EH table data for 32-bit and 64-bit functions using
@@ -76,6 +79,10 @@ public:
 
   /// Gather and emit post-function exception information.
   void endFunction(const MachineFunction *) override;
+
+  /// \brief Emit target-specific EH funclet machinery.
+  void beginFunclet(const MachineBasicBlock &MBB, MCSymbol *Sym) override;
+  void endFunclet() override;
 };
 }
 
index 3e80cd8e5dbdde2c5d7ca474016fbaa138848991..8b0ef1b0ebc3d23e3c57aed6ec6a5ff564d2d810 100644 (file)
@@ -1182,6 +1182,7 @@ void SelectionDAGBuilder::visitCleanupPad(const CleanupPadInst &CPI) {
   // Don't emit any special code for the cleanuppad instruction. It just marks
   // the start of a funclet.
   FuncInfo.MBB->setIsEHFuncletEntry();
+  FuncInfo.MBB->setIsCleanupFuncletEntry();
 }
 
 /// When an invoke or a cleanupret unwinds to the next EH pad, there are
index e4c35b115e0e08c827f542c27a576809f176b94e..0e6b5c4b4045b2cdae19825d99780f5b52773140 100644 (file)
@@ -713,8 +713,6 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
       // Reset EBP / ESI to something good.
       MBBI = restoreWin32EHStackPointers(MBB, MBBI, DL);
     } else {
-      // FIXME: Add SEH directives.
-      NeedsWinCFI = false;
       // Immediately spill RDX into the home slot. The runtime cares about this.
       unsigned RDX = Uses64BitFramePtr ? X86::RDX : X86::EDX;
       // MOV64mr %rdx, 16(%rsp)
@@ -727,6 +725,9 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
       BuildMI(MBB, MBBI, DL, TII.get(X86::PUSH64r))
           .addReg(MachineFramePtr, RegState::Kill)
           .setMIFlag(MachineInstr::FrameSetup);
+      BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_PushReg))
+          .addImm(MachineFramePtr)
+          .setMIFlag(MachineInstr::FrameSetup);
       // MOV64rr %rdx, %rbp
       unsigned MOVrr = Uses64BitFramePtr ? X86::MOV64rr : X86::MOV32rr;
       BuildMI(MBB, MBBI, DL, TII.get(MOVrr), FramePtr)
index d4ff04c9fe1ba1863bc6646e5d218e7c26eabb71..51ffe7bb3bd503f37078745d4dfabd2c9ee6d14f 100644 (file)
@@ -35,6 +35,9 @@ __try.cont:                                       ; preds = %lpad1, %entry
 ; CHECK: .seh_handler __C_specific_handler
 ; CHECK-NOT: jmpq *
 ; CHECK: .seh_handlerdata
+; CHECK-NEXT: .text
+; CHECK: .seh_endproc
+; CHECK: .section .xdata,"dr"
 ; CHECK-NEXT: .long 1
 ; CHECK-NEXT: .long .Ltmp{{.*}}
 ; CHECK-NEXT: .long .Ltmp{{.*}}
index 82064c2a390781e33f82a353ed815ed1a46b98b8..92ea539bcf77a9fe59f61beaffbb67eecccad9bf 100644 (file)
@@ -18,9 +18,9 @@ define i32 @main() uwtable optsize ssp personality i8* bitcast (i32 (...)* @__gx
 ; MINGW64: .seh_setframe 5, 32
 ; MINGW64: callq _Unwind_Resume
 ; MINGW64: .seh_handlerdata
+; MINGW64: .seh_endproc
 ; MINGW64: GCC_except_table0:
 ; MINGW64: Lexception0:
-; MINGW64: .seh_endproc
 
 ; MINGW32: .cfi_startproc
 ; MINGW32: .cfi_personality 0, ___gxx_personality_v0
index 1c1a3c2139d6de0f723e0c0e6cbae7377ef8e338..00a2455655bc41917cf62f9b2ebd9a3f300d5cdd 100644 (file)
@@ -38,6 +38,10 @@ eh.resume:
 ; CHECK: callq printf
 
 ; CHECK: .seh_handlerdata
+; CHECK-NEXT: .text
+; CHECK-NEXT: .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .seh_endproc
+; CHECK-NEXT: .section .xdata,"dr"
 ; CHECK-NEXT: .long 1
 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}}@IMGREL
 ; CHECK-NEXT: .long .Ltmp{{[0-9]+}}@IMGREL+1
index 0630d001bb7647f080d99dcb7c1bdf55378a563b..5a529cd8d7a0bb407d8205d846091aef25c9eb69 100644 (file)
@@ -103,6 +103,10 @@ eh.resume:                                        ; preds = %catch.dispatch
 ; CHECK: retq
 ;
 ; CHECK: .seh_handlerdata
+; CHECK-NEXT: .text
+; CHECK-NEXT: .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .seh_endproc
+; CHECK-NEXT: .section .xdata,"dr"
 ; CHECK-NEXT: .long 3
 ; CHECK-NEXT: .long .Ltmp0@IMGREL
 ; CHECK-NEXT: .long .Ltmp1@IMGREL+1
index 350cd932f4815a77e8fdfa2572bf1eecebe570a0..99f3b658a512ff48b575b235dea26400f93e8ba6 100644 (file)
@@ -38,6 +38,10 @@ terminate.lpad:                                   ; preds = %lpad
 ; X64: retq
 
 ; X64: .seh_handlerdata
+; X64-NEXT: .text
+; X64-NEXT: .Ltmp{{[0-9]+}}:
+; X64-NEXT: .seh_endproc
+; X64-NEXT: .section .xdata,"dr"
 ; X64-NEXT: .long 1
 ; X64-NEXT: .long .Ltmp0@IMGREL
 ; X64-NEXT: .long .Ltmp1@IMGREL
index 699e58ee8bae8fd45c3094e901cf6237c8fef432..cd0ef7171957b759de3d7da093dad164a7c196c1 100644 (file)
@@ -90,6 +90,10 @@ __try.cont:
 ; CHECK: jmp [[cont_bb]]
 
 ; CHECK: .seh_handlerdata
+; CHECK-NEXT: .text
+; CHECK-NEXT: .Ltmp{{[0-9]+}}
+; CHECK-NEXT: .seh_endproc
+; CHECK-NEXT: .section .xdata,"dr"
 ; CHECK-NEXT: .long 2
 ; CHECK-NEXT: .long .Ltmp0@IMGREL
 ; CHECK-NEXT: .long .Ltmp1@IMGREL+1
index c64dcfe058d8daea6dfdd96ffe4b429d5dd9df77..6603f4e6d927e4e942ba2636d63322da61dbc1e0 100644 (file)
@@ -71,7 +71,8 @@ catchendblock:                                    ; preds = %catch,
 ; X86: addl $12, %ebp
 ; X86: jmp [[contbb]]
 
-; X86: [[catch1bb:LBB0_[0-9]+]]: # %catch{{$}}
+; X86: "?catch$[[catch1bb:[0-9]+]]@?0?try_catch_catch@4HA":
+; X86: LBB0_[[catch1bb]]: # %catch{{$}}
 ; X86: pushl %ebp
 ; X86-NOT: pushl
 ; X86: addl $12, %ebp
@@ -89,7 +90,7 @@ catchendblock:                                    ; preds = %catch,
 ; X86:   .long   0
 ; X86:   .long   "??_R0H@8"
 ; X86:   .long   0
-; X86:   .long   [[catch1bb]]
+; X86:   .long   "?catch$[[catch1bb]]@?0?try_catch_catch@4HA"
 
 ; X64-LABEL: try_catch_catch:
 ; X64: pushq %rbp
@@ -116,7 +117,8 @@ catchendblock:                                    ; preds = %catch,
 ; X64: popq %rbp
 ; X64: retq
 
-; X64: [[catch1bb:\.LBB0_[0-9]+]]: # %catch{{$}}
+; X64: "?catch$[[catch1bb:[0-9]+]]@?0?try_catch_catch@4HA":
+; X64: LBB0_[[catch1bb]]: # %catch{{$}}
 ; X64: movq %rdx, 16(%rsp)
 ; X64: pushq %rbp
 ; X64: movq %rdx, %rbp
@@ -132,5 +134,5 @@ catchendblock:                                    ; preds = %catch,
 ; X64:   .long   0
 ; X64:   .long   "??_R0H@8"@IMGREL
 ; X64:   .long   0
-; X64:   .long   [[catch1bb]]@IMGREL
+; X64:   .long   "?catch$[[catch1bb]]@?0?try_catch_catch@4HA"@IMGREL
 ; X64:   .long   56
index 597f0e8ae801f468fddebfb85bb2bcefc6468940..7af13e67975c6547fcfb08b8b9644c91fd58cbb2 100644 (file)
@@ -78,7 +78,8 @@ catchendblock:                                    ; preds = %catch, %catch.2, %c
 ; X86: addl $12, %ebp
 ; X86: jmp [[contbb]]
 
-; X86: [[catch1bb:LBB0_[0-9]+]]: # %catch{{$}}
+; X86: "?catch$[[catch1bb:[0-9]+]]@?0?try_catch_catch@4HA":
+; X86: LBB0_[[catch1bb]]: # %catch{{$}}
 ; X86: pushl %ebp
 ; X86: addl $12, %ebp
 ; X86: subl $8, %esp
@@ -93,7 +94,8 @@ catchendblock:                                    ; preds = %catch, %catch.2, %c
 ; X86-NEXT: movl $[[restorebb]], %eax
 ; X86-NEXT: retl
 
-; X86: [[catch2bb:LBB0_[0-9]+]]: # %catch.2{{$}}
+; X86: "?catch$[[catch2bb:[0-9]+]]@?0?try_catch_catch@4HA":
+; X86: LBB0_[[catch2bb]]: # %catch.2{{$}}
 ; X86: pushl %ebp
 ; X86: addl $12, %ebp
 ; X86: subl $8, %esp
@@ -112,11 +114,11 @@ catchendblock:                                    ; preds = %catch, %catch.2, %c
 ; X86-NEXT:   .long   0
 ; X86-NEXT:   .long   "??_R0H@8"
 ; X86-NEXT:   .long   -20
-; X86-NEXT:   .long   [[catch1bb]]
+; X86-NEXT:   .long   "?catch$[[catch1bb]]@?0?try_catch_catch@4HA"
 ; X86-NEXT:   .long   64
 ; X86-NEXT:   .long   0
 ; X86-NEXT:   .long   0
-; X86-NEXT:   .long   [[catch2bb]]
+; X86-NEXT:   .long   "?catch$[[catch2bb]]@?0?try_catch_catch@4HA"
 
 ; X64-LABEL: try_catch_catch:
 ; X64: Lfunc_begin0:
@@ -135,7 +137,8 @@ catchendblock:                                    ; preds = %catch, %catch.2, %c
 ; X64: popq %rbp
 ; X64: retq
 
-; X64: [[catch1bb:\.LBB0_[0-9]+]]: # %catch{{$}}
+; X64: "?catch$[[catch1bb:[0-9]+]]@?0?try_catch_catch@4HA":
+; X64: LBB0_[[catch1bb]]: # %catch{{$}}
 ; X64: movq %rdx, 16(%rsp)
 ; X64: pushq %rbp
 ; X64: movq %rdx, %rbp
@@ -149,7 +152,8 @@ catchendblock:                                    ; preds = %catch, %catch.2, %c
 ; X64-NEXT: leaq [[contbb]](%rip), %rax
 ; X64-NEXT: retq
 
-; X64: [[catch2bb:\.LBB0_[0-9]+]]: # %catch.2{{$}}
+; X64: "?catch$[[catch2bb:[0-9]+]]@?0?try_catch_catch@4HA":
+; X64: LBB0_[[catch2bb]]: # %catch.2{{$}}
 ; X64: movq %rdx, 16(%rsp)
 ; X64: pushq %rbp
 ; X64: movq %rdx, %rbp
@@ -187,12 +191,12 @@ catchendblock:                                    ; preds = %catch, %catch.2, %c
 ; X64-NEXT:   .long   "??_R0H@8"@IMGREL
 ; FIXME: This should probably be offset from rsp, not rbp.
 ; X64-NEXT:   .long   [[e_addr]]
-; X64-NEXT:   .long   [[catch1bb]]@IMGREL
+; X64-NEXT:   .long   "?catch$[[catch1bb]]@?0?try_catch_catch@4HA"@IMGREL
 ; X64-NEXT:   .long   56
 ; X64-NEXT:   .long   64
 ; X64-NEXT:   .long   0
 ; X64-NEXT:   .long   0
-; X64-NEXT:   .long   [[catch2bb]]@IMGREL
+; X64-NEXT:   .long   "?catch$[[catch2bb]]@?0?try_catch_catch@4HA"@IMGREL
 ; X64-NEXT:   .long   56
 
 ; X64: $ip2state$try_catch_catch:
index a08fd976fa96b908afa2433b593ebb63c56bf6ec..02ead25603fbc4d0ddf91c1f8515b1444b2c709e 100644 (file)
@@ -65,14 +65,16 @@ cleanup.outer:                                      ; preds = %invoke.cont.1, %c
 ; X86: movl    $3, (%esp)
 ; X86: calll   _f
 
-; X86: LBB1_[[cleanup_inner:[0-9]+]]: # %cleanup.inner
+; X86: "?dtor$[[cleanup_inner:[0-9]+]]@?0?nested_cleanup@4HA":
+; X86: LBB1_[[cleanup_inner]]: # %cleanup.inner{{$}}
 ; X86: pushl %ebp
 ; X86: leal    {{.*}}(%ebp), %ecx
 ; X86: calll   "??1Dtor@@QAE@XZ"
 ; X86: popl %ebp
 ; X86: retl
 
-; X86: LBB1_[[cleanup_outer:[0-9]+]]: # %cleanup.outer
+; X86: "?dtor$[[cleanup_outer:[0-9]+]]@?0?nested_cleanup@4HA":
+; X86: LBB1_[[cleanup_outer]]: # %cleanup.outer{{$}}
 ; X86: pushl %ebp
 ; X86: leal    {{.*}}(%ebp), %ecx
 ; X86: calll   "??1Dtor@@QAE@XZ"
@@ -91,41 +93,46 @@ cleanup.outer:                                      ; preds = %invoke.cont.1, %c
 ; X86:         .long   1
 ; X86: $stateUnwindMap$nested_cleanup:
 ; X86:         .long   -1
-; X86:         .long   LBB1_[[cleanup_outer]]
+; X86:         .long   "?dtor$[[cleanup_outer]]@?0?nested_cleanup@4HA"
 ; X86:         .long   0
-; X86:         .long   LBB1_[[cleanup_inner]]
+; X86:         .long   "?dtor$[[cleanup_inner]]@?0?nested_cleanup@4HA"
 
 ; X64-LABEL: nested_cleanup:
 ; X64: .Lfunc_begin1:
-; X64: .Ltmp8:
+; X64: .Ltmp14:
 ; X64: movl    $1, %ecx
 ; X64: callq   f
-; X64: .Ltmp10:
+; X64: .Ltmp16:
 ; X64: movl    $2, %ecx
 ; X64: callq   f
-; X64: .Ltmp11:
+; X64: .Ltmp17:
 ; X64: callq   "??1Dtor@@QAE@XZ"
-; X64: .Ltmp12:
+; X64: .Ltmp18:
 ; X64: movl    $3, %ecx
 ; X64: callq   f
-; X64: .Ltmp13:
+; X64: .Ltmp19:
 
-; X64: .LBB1_[[cleanup_inner:[0-9]+]]: # %cleanup.inner
+; X64: "?dtor$[[cleanup_inner:[0-9]+]]@?0?nested_cleanup@4HA":
+; X64: LBB1_[[cleanup_inner]]: # %cleanup.inner{{$}}
 ; X64: pushq %rbp
 ; X64: leaq    {{.*}}(%rbp), %rcx
 ; X64: callq   "??1Dtor@@QAE@XZ"
 ; X64: popq %rbp
 ; X64: retq
 
-; X64: .LBB1_[[cleanup_outer:[0-9]+]]: # %cleanup.outer
+; X64:        .seh_handlerdata
+; X64:        .text
+; X64:        .seh_endproc
+
+; X64: "?dtor$[[cleanup_outer:[0-9]+]]@?0?nested_cleanup@4HA":
+; X64: LBB1_[[cleanup_outer]]: # %cleanup.outer{{$}}
 ; X64: pushq %rbp
 ; X64: leaq    {{.*}}(%rbp), %rcx
 ; X64: callq   "??1Dtor@@QAE@XZ"
 ; X64: popq %rbp
 ; X64: retq
 
-; X64: .seh_handlerdata
-; X64-NEXT: .long   ($cppxdata$nested_cleanup)@IMGREL
+; X64:        .section .xdata,"dr"
 ; X64-NEXT: .align  4
 ; X64: $cppxdata$nested_cleanup:
 ; X64-NEXT: .long   429065506
@@ -141,20 +148,20 @@ cleanup.outer:                                      ; preds = %invoke.cont.1, %c
 
 ; X64: $stateUnwindMap$nested_cleanup:
 ; X64-NEXT: .long   -1
-; X64-NEXT: .long   .LBB1_[[cleanup_outer]]@IMGREL
+; X64-NEXT: .long   "?dtor$[[cleanup_outer]]@?0?nested_cleanup@4HA"@IMGREL
 ; X64-NEXT: .long   0
-; X64-NEXT: .long   .LBB1_[[cleanup_inner]]@IMGREL
+; X64-NEXT: .long   "?dtor$[[cleanup_inner]]@?0?nested_cleanup@4HA"@IMGREL
 
 ; X64: $ip2state$nested_cleanup:
 ; X64-NEXT: .long   .Lfunc_begin1@IMGREL
 ; X64-NEXT: .long   -1
-; X64-NEXT: .long   .Ltmp8@IMGREL
+; X64-NEXT: .long   .Ltmp14@IMGREL
 ; X64-NEXT: .long   0
-; X64-NEXT: .long   .Ltmp10@IMGREL
+; X64-NEXT: .long   .Ltmp16@IMGREL
 ; X64-NEXT: .long   1
-; X64-NEXT: .long   .Ltmp12@IMGREL
+; X64-NEXT: .long   .Ltmp18@IMGREL
 ; X64-NEXT: .long   0
-; X64-NEXT: .long   .Ltmp13@IMGREL+1
+; X64-NEXT: .long   .Ltmp19@IMGREL+1
 ; X64-NEXT: .long   -1
 
 attributes #0 = { "disable-tail-calls"="false" "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" }
diff --git a/test/CodeGen/X86/win-funclet-cfi.ll b/test/CodeGen/X86/win-funclet-cfi.ll
new file mode 100644 (file)
index 0000000..3088379
--- /dev/null
@@ -0,0 +1,100 @@
+; RUN: llc -mtriple=x86_64-windows-msvc < %s | FileCheck %s
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @"\01?f@@YAXXZ"(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
+entry:
+  invoke void @g()
+          to label %unreachable unwind label %cleanupblock
+
+cleanupblock:
+  %cleanp = cleanuppad []
+  call void @g()
+  cleanupret %cleanp unwind label %catch.dispatch
+
+catch.dispatch:
+  %cp = catchpad [i8* null, i32 64, i8* null]
+          to label %catch unwind label %catchendblock
+
+catch:
+  call void @g()
+  catchret %cp to label %try.cont
+
+try.cont:
+  ret void
+
+catchendblock:
+  catchendpad unwind to caller
+
+unreachable:
+  unreachable
+}
+
+
+declare void @g()
+
+declare i32 @__CxxFrameHandler3(...)
+
+; Destructors need CFI but they shouldn't use the .seh_handler directive.
+; CHECK: "?dtor$[[cleanup:[0-9]+]]@?0??f@@YAXXZ@4HA":
+; CHECK: .seh_proc "?dtor$[[cleanup]]@?0??f@@YAXXZ@4HA"
+; CHECK-NOT: .seh_handler __CxxFrameHandler3
+; CHECK: LBB0_[[cleanup]]: # %cleanupblock{{$}}
+
+; Emit CFI for pushing RBP.
+; CHECK: movq    %rdx, 16(%rsp)
+; CHECK: pushq   %rbp
+; CHECK: .seh_pushreg 5
+
+; Emit CFI for allocating from the stack pointer.
+; CHECK: subq    $32, %rsp
+; CHECK: .seh_stackalloc 32
+
+; FIXME: This looks wrong...
+; CHECK: leaq    32(%rsp), %rbp
+; CHECK: .seh_setframe 5, 32
+
+; Prologue is done, emit the .seh_endprologue directive.
+; CHECK: .seh_endprologue
+
+; Make sure there is a nop after a call if the call precedes the epilogue.
+; CHECK: callq g
+; CHECK-NEXT: nop
+
+; Don't emit a reference to the LSDA.
+; CHECK: .seh_handlerdata
+; CHECK-NOT:  .long   ("$cppxdata$?f@@YAXXZ")@IMGREL
+; CHECK-NEXT: .text
+; CHECK: .seh_endproc
+
+; CHECK: "?catch$[[catch:[0-9]+]]@?0??f@@YAXXZ@4HA":
+; CHECK: .seh_proc "?catch$[[catch]]@?0??f@@YAXXZ@4HA"
+; CHECK-NEXT: .seh_handler __CxxFrameHandler3, @unwind, @except
+; CHECK: LBB0_[[catch]]: # %catch{{$}}
+
+; Emit CFI for pushing RBP.
+; CHECK: movq    %rdx, 16(%rsp)
+; CHECK: pushq   %rbp
+; CHECK: .seh_pushreg 5
+
+; Emit CFI for allocating from the stack pointer.
+; CHECK: subq    $32, %rsp
+; CHECK: .seh_stackalloc 32
+
+; FIXME: This looks wrong...
+; CHECK: leaq    32(%rsp), %rbp
+; CHECK: .seh_setframe 5, 32
+
+; Prologue is done, emit the .seh_endprologue directive.
+; CHECK: .seh_endprologue
+
+; Make sure there is a nop after a call if the call precedes the epilogue.
+; CHECK: callq g
+; CHECK-NEXT: nop
+
+; Emit a reference to the LSDA.
+; CHECK: .seh_handlerdata
+; CHECK-NEXT:  .long   ("$cppxdata$?f@@YAXXZ")@IMGREL
+; CHECK-NEXT: .text
+; CHECK: .seh_endproc