diff options
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/include/llvm/CodeGen/WinEHFuncInfo.h | 2 | ||||
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/EHStreamer.h | 8 | ||||
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/WinException.cpp | 245 | ||||
-rw-r--r-- | llvm/lib/CodeGen/WinEHPrepare.cpp | 28 | ||||
-rw-r--r-- | llvm/lib/Target/X86/X86FrameLowering.cpp | 19 | ||||
-rw-r--r-- | llvm/test/CodeGen/X86/seh-catchpad.ll | 202 |
6 files changed, 439 insertions, 65 deletions
diff --git a/llvm/include/llvm/CodeGen/WinEHFuncInfo.h b/llvm/include/llvm/CodeGen/WinEHFuncInfo.h index 79f21687302..5d122094ff8 100644 --- a/llvm/include/llvm/CodeGen/WinEHFuncInfo.h +++ b/llvm/include/llvm/CodeGen/WinEHFuncInfo.h @@ -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; diff --git a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h index e42e082acbf..c6a0e9d0524 100644 --- a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h +++ b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h @@ -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); }; } diff --git a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp index f4a279e5fe8..b0c6b7d11e4 100644 --- a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp @@ -121,6 +121,10 @@ void WinException::endFunction(const MachineFunction *MF) { 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::getLabelPlusOne(MCSymbol *Label) { 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::getLabelPlusOne(MCSymbol *Label) { /// } 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::emitCSpecificHandlerTable(const MachineFunction *MF) { // 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::emitCSpecificHandlerTable(const MachineFunction *MF) { 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::emitCSpecificHandlerTable(const MachineFunction *MF) { // 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::emitCXXFrameHandler3Table(const MachineFunction *MF) { 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; } } diff --git a/llvm/lib/CodeGen/WinEHPrepare.cpp b/llvm/lib/CodeGen/WinEHPrepare.cpp index 07734c352c0..3b6187594e9 100644 --- a/llvm/lib/CodeGen/WinEHPrepare.cpp +++ b/llvm/lib/CodeGen/WinEHPrepare.cpp @@ -2724,16 +2724,28 @@ static void calculateExplicitCXXStateNumbers(WinEHFuncInfo &FuncInfo, } } -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 calculateExplicitSEHStateNumbers(WinEHFuncInfo &FuncInfo, "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 calculateExplicitSEHStateNumbers(WinEHFuncInfo &FuncInfo, 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'); diff --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp index fc192cd6bfd..c2c9f07ee10 100644 --- a/llvm/lib/Target/X86/X86FrameLowering.cpp +++ b/llvm/lib/Target/X86/X86FrameLowering.cpp @@ -1489,10 +1489,21 @@ bool X86FrameLowering::restoreCalleeSavedRegisters(MachineBasicBlock &MBB, 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); diff --git a/llvm/test/CodeGen/X86/seh-catchpad.ll b/llvm/test/CodeGen/X86/seh-catchpad.ll new file mode 100644 index 00000000000..e69bc018d83 --- /dev/null +++ b/llvm/test/CodeGen/X86/seh-catchpad.ll @@ -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@_07MKBLAIAL@finally?$AA@" = comdat any + +$"\01??_C@_06IBDBCMGJ@caught?$AA@" = comdat any + +@"\01??_C@_07MKBLAIAL@finally?$AA@" = linkonce_odr unnamed_addr constant [8 x i8] c"finally\00", comdat, align 1 +@"\01??_C@_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@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@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@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@_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@0@main@@" +; CHECK: jmp .LBB1_[[epilogue]] +; CHECK: .LBB1_[[except2bb:[0-9]+]]: # %__except.ret +; CHECK: leaq "??_C@_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@IMGREL +; CHECK-NEXT: .long .Ltmp1@IMGREL+1 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .LBB1_[[except1bb]]@IMGREL +; CHECK-NEXT: .long .Ltmp0@IMGREL +; CHECK-NEXT: .long .Ltmp1@IMGREL+1 +; CHECK-NEXT: .long "?filt$0@0@main@@"@IMGREL +; CHECK-NEXT: .long .LBB1_[[except2bb]]@IMGREL +; CHECK-NEXT: .long .Ltmp2@IMGREL +; CHECK-NEXT: .long .Ltmp3@IMGREL+1 +; CHECK-NEXT: .long .LBB1_[[finbb:[0-9]+]]@IMGREL +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long .Ltmp2@IMGREL +; CHECK-NEXT: .long .Ltmp3@IMGREL+1 +; CHECK-NEXT: .long "?filt$0@0@main@@"@IMGREL +; CHECK-NEXT: .long .LBB1_6@IMGREL +; CHECK-NEXT: .Ltmp14: + +; CHECK: .text +; CHECK: .seh_endproc + +; CHECK: "?dtor$4@?0?main@4HA": +; CHECK: .seh_proc "?dtor$4@?0?main@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@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@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@0@main@@": # @"\01?filt$0@0@main@@" +; CHECK: .seh_proc "?filt$0@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@0@main@@"() #2 { +entry: + %call = tail call i32 @puts(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @"\01??_C@_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 } |