Index: include/llvm/CodeGen/MachineBasicBlock.h =================================================================== --- include/llvm/CodeGen/MachineBasicBlock.h +++ include/llvm/CodeGen/MachineBasicBlock.h @@ -114,6 +114,9 @@ /// 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 @@ /// 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: include/llvm/CodeGen/WinEHFuncInfo.h =================================================================== --- include/llvm/CodeGen/WinEHFuncInfo.h +++ include/llvm/CodeGen/WinEHFuncInfo.h @@ -118,7 +118,7 @@ // exceptions on Windows. typedef PointerUnion MBBOrBasicBlock; -typedef PointerUnion ValueOrMBB; +typedef PointerUnion ValueOrMBB; struct WinEHUnwindMapEntry { int ToState; Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -2459,6 +2459,14 @@ /// MachineBasicBlock, an alignment (if present) and a comment describing /// it if appropriate. void AsmPrinter::EmitBasicBlockStart(const MachineBasicBlock &MBB) const { + // Emit pre-funclet information. + 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: lib/CodeGen/AsmPrinter/AsmPrinterHandler.h =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinterHandler.h +++ lib/CodeGen/AsmPrinter/AsmPrinterHandler.h @@ -19,6 +19,7 @@ namespace llvm { +class MachineBasicBlock; class MachineFunction; class MachineInstr; class MCSymbol; @@ -50,6 +51,11 @@ /// 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: lib/CodeGen/AsmPrinter/WinException.h =================================================================== --- lib/CodeGen/AsmPrinter/WinException.h +++ lib/CodeGen/AsmPrinter/WinException.h @@ -36,6 +36,9 @@ /// 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 @@ /// 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: lib/CodeGen/AsmPrinter/WinException.cpp =================================================================== --- lib/CodeGen/AsmPrinter/WinException.cpp +++ lib/CodeGen/AsmPrinter/WinException.cpp @@ -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 @@ 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 @@ 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 @@ 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()) { + auto *MBB = Handler.get(); + 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(Handler.get())); +} + +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(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 @@ } } -/// 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()) - return Handler.get()->getSymbol(); - return Asm->getSymbol(cast(Handler.get())); -} - void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) { const Function *F = MF->getFunction(); auto &OS = *Asm->OutStreamer; @@ -323,7 +414,6 @@ // 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: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -1182,6 +1182,7 @@ // 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: lib/Target/X86/X86FrameLowering.cpp =================================================================== --- lib/Target/X86/X86FrameLowering.cpp +++ lib/Target/X86/X86FrameLowering.cpp @@ -713,8 +713,6 @@ // 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 @@ 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: test/CodeGen/WinEH/seh-prepared-basic.ll =================================================================== --- test/CodeGen/WinEH/seh-prepared-basic.ll +++ test/CodeGen/WinEH/seh-prepared-basic.ll @@ -35,6 +35,9 @@ ; 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: test/CodeGen/X86/gcc_except_table.ll =================================================================== --- test/CodeGen/X86/gcc_except_table.ll +++ test/CodeGen/X86/gcc_except_table.ll @@ -18,9 +18,9 @@ ; 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: test/CodeGen/X86/seh-catch-all.ll =================================================================== --- test/CodeGen/X86/seh-catch-all.ll +++ test/CodeGen/X86/seh-catch-all.ll @@ -38,6 +38,10 @@ ; 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: test/CodeGen/X86/seh-except-finally.ll =================================================================== --- test/CodeGen/X86/seh-except-finally.ll +++ test/CodeGen/X86/seh-except-finally.ll @@ -103,6 +103,10 @@ ; 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: test/CodeGen/X86/seh-finally.ll =================================================================== --- test/CodeGen/X86/seh-finally.ll +++ test/CodeGen/X86/seh-finally.ll @@ -38,6 +38,10 @@ ; 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: test/CodeGen/X86/seh-safe-div.ll =================================================================== --- test/CodeGen/X86/seh-safe-div.ll +++ test/CodeGen/X86/seh-safe-div.ll @@ -90,6 +90,10 @@ ; 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: test/CodeGen/X86/win-catchpad-csrs.ll =================================================================== --- test/CodeGen/X86/win-catchpad-csrs.ll +++ test/CodeGen/X86/win-catchpad-csrs.ll @@ -71,7 +71,7 @@ ; X86: addl $12, %ebp ; X86: jmp [[contbb]] -; X86: [[catch1bb:LBB0_[0-9]+]]: # %catch{{$}} +; X86: "?catch$[[catch1bb:[0-9]+]]@?0?try_catch_catch@4HA": ; X86: pushl %ebp ; X86-NOT: pushl ; X86: addl $12, %ebp @@ -89,7 +89,7 @@ ; 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 +116,7 @@ ; X64: popq %rbp ; X64: retq -; X64: [[catch1bb:\.LBB0_[0-9]+]]: # %catch{{$}} +; X64: "?catch$[[catch1bb:[0-9]+]]@?0?try_catch_catch@4HA": ; X64: movq %rdx, 16(%rsp) ; X64: pushq %rbp ; X64: movq %rdx, %rbp @@ -132,5 +132,5 @@ ; 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: test/CodeGen/X86/win-catchpad.ll =================================================================== --- test/CodeGen/X86/win-catchpad.ll +++ test/CodeGen/X86/win-catchpad.ll @@ -78,7 +78,7 @@ ; X86: addl $12, %ebp ; X86: jmp [[contbb]] -; X86: [[catch1bb:LBB0_[0-9]+]]: # %catch{{$}} +; X86: "?catch$[[catch1bb:[0-9]+]]@?0?try_catch_catch@4HA": ; X86: pushl %ebp ; X86: addl $12, %ebp ; X86: subl $8, %esp @@ -93,7 +93,7 @@ ; 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: pushl %ebp ; X86: addl $12, %ebp ; X86: subl $8, %esp @@ -112,11 +112,11 @@ ; 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 +135,7 @@ ; X64: popq %rbp ; X64: retq -; X64: [[catch1bb:\.LBB0_[0-9]+]]: # %catch{{$}} +; X64: "?catch$[[catch1bb:[0-9]+]]@?0?try_catch_catch@4HA": ; X64: movq %rdx, 16(%rsp) ; X64: pushq %rbp ; X64: movq %rdx, %rbp @@ -149,7 +149,7 @@ ; 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: movq %rdx, 16(%rsp) ; X64: pushq %rbp ; X64: movq %rdx, %rbp @@ -187,12 +187,12 @@ ; 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: test/CodeGen/X86/win-cleanuppad.ll =================================================================== --- test/CodeGen/X86/win-cleanuppad.ll +++ test/CodeGen/X86/win-cleanuppad.ll @@ -65,14 +65,14 @@ ; 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: 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: pushl %ebp ; X86: leal {{.*}}(%ebp), %ecx ; X86: calll "??1Dtor@@QAE@XZ" @@ -91,41 +91,44 @@ ; 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: 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: 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 +144,20 @@ ; 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" } Index: test/CodeGen/X86/win-funclet-cfi.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/win-funclet-cfi.ll @@ -0,0 +1,98 @@ +; 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 + +; 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 + +; 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