llvm.org GIT mirror llvm / 646073b
[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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@249078 91177308-0d34-0410-b5e6-96231b3b80d8 Reid Kleckner 4 years ago
6 changed file(s) with 439 addition(s) and 65 deletion(s). Raw diff Collapse all Expand all
130130 /// this state. This indexes into SEHUnwindMap.
131131 int ToState = -1;
132132
133 bool IsFinally = false;
134
133135 /// Holds the filter expression function.
134136 const Function *Filter = nullptr;
135137
7575 SmallVectorImpl &Actions,
7676 SmallVectorImpl &FirstActions);
7777
78 /// Return `true' if this is a call to a function marked `nounwind'. Return
79 /// `false' otherwise.
80 bool callToNoUnwindFunction(const MachineInstr *MI);
81
8278 void computePadMap(const SmallVectorImpl &LandingPads,
8379 RangeMapType &PadMap);
8480
130126 void setSymbolSize(const MCSymbol *Sym, uint64_t Size) override {}
131127 void beginInstruction(const MachineInstr *MI) override {}
132128 void endInstruction() override {}
129
130 /// Return `true' if this is a call to a function marked `nounwind'. Return
131 /// `false' otherwise.
132 static bool callToNoUnwindFunction(const MachineInstr *MI);
133133 };
134134 }
135135
120120
121121 endFunclet();
122122
123 // endFunclet will emit the necessary .xdata tables for x64 SEH.
124 if (Per == EHPersonality::MSVC_Win64SEH && MMI->hasEHFunclets())
125 return;
126
123127 if (shouldEmitPersonality || shouldEmitLSDA) {
124128 Asm->OutStreamer->PushSection();
125129
236240 // Emit an UNWIND_INFO struct describing the prologue.
237241 Asm->OutStreamer->EmitWinEHHandlerData();
238242
239 // If this is a C++ catch funclet (or the parent function),
240 // emit a reference to the LSDA for the parent function.
241243 if (Per == EHPersonality::MSVC_CXX && shouldEmitPersonality &&
242244 !CurrentFuncletEntry->isCleanupFuncletEntry()) {
245 // If this is a C++ catch funclet (or the parent function),
246 // emit a reference to the LSDA for the parent function.
243247 StringRef FuncLinkageName = GlobalValue::getRealLinkageName(F->getName());
244248 MCSymbol *FuncInfoXData = Asm->OutContext.getOrCreateSymbol(
245249 Twine("$cppxdata$", FuncLinkageName));
246250 Asm->OutStreamer->EmitValue(create32bitRef(FuncInfoXData), 4);
251 } else if (Per == EHPersonality::MSVC_Win64SEH && MMI->hasEHFunclets() &&
252 !CurrentFuncletEntry->isEHFuncletEntry()) {
253 // If this is the parent function in Win64 SEH, emit the LSDA immediately
254 // following .seh_handlerdata.
255 emitCSpecificHandlerTable(Asm->MF);
247256 }
248257
249258 // Switch back to the previous section now that we are done writing to
280289 return MCBinaryExpr::createAdd(create32bitRef(Label),
281290 MCConstantExpr::create(1, Asm->OutContext),
282291 Asm->OutContext);
292 }
293
294 /// Information describing an invoke range.
295 struct InvokeRange {
296 MCSymbol *BeginLabel = nullptr;
297 MCSymbol *EndLabel = nullptr;
298 int State = -1;
299
300 /// If we saw a potentially throwing call between this range and the last
301 /// range.
302 bool SawPotentiallyThrowing = false;
303 };
304
305 /// Iterator over the begin/end label pairs of invokes within a basic block.
306 class InvokeLabelIterator {
307 public:
308 InvokeLabelIterator(WinEHFuncInfo &EHInfo,
309 MachineBasicBlock::const_iterator MBBI,
310 MachineBasicBlock::const_iterator MBBIEnd)
311 : EHInfo(EHInfo), MBBI(MBBI), MBBIEnd(MBBIEnd) {
312 scan();
313 }
314
315 // Iterator methods.
316 bool operator==(const InvokeLabelIterator &o) const { return MBBI == o.MBBI; }
317 bool operator!=(const InvokeLabelIterator &o) const { return MBBI != o.MBBI; }
318 InvokeRange &operator*() { return CurRange; }
319 InvokeRange *operator->() { return &CurRange; }
320 InvokeLabelIterator &operator++() { return scan(); }
321
322 private:
323 // Scan forward to find the next invoke range, or hit the end iterator.
324 InvokeLabelIterator &scan();
325
326 WinEHFuncInfo &EHInfo;
327 MachineBasicBlock::const_iterator MBBI;
328 MachineBasicBlock::const_iterator MBBIEnd;
329 InvokeRange CurRange;
330 };
331
332 /// Invoke label range iteration logic. Increment MBBI until we find the next
333 /// EH_LABEL pair, and then update MBBI to point after the end label.
334 InvokeLabelIterator &InvokeLabelIterator::scan() {
335 // Reset our state.
336 CurRange = InvokeRange{};
337
338 for (const MachineInstr &MI : make_range(MBBI, MBBIEnd)) {
339 // Remember if we had to cross a potentially throwing call instruction that
340 // must unwind to caller.
341 if (MI.isCall()) {
342 CurRange.SawPotentiallyThrowing |=
343 !EHStreamer::callToNoUnwindFunction(&MI);
344 continue;
345 }
346 // Find the next EH_LABEL instruction.
347 if (!MI.isEHLabel())
348 continue;
349
350 // If this is a begin label, break out with the state and end label.
351 // Otherwise this is probably a CFI EH_LABEL that we should continue past.
352 MCSymbol *Label = MI.getOperand(0).getMCSymbol();
353 auto StateAndEnd = EHInfo.InvokeToStateMap.find(Label);
354 if (StateAndEnd == EHInfo.InvokeToStateMap.end())
355 continue;
356 MBBI = MachineBasicBlock::const_iterator(&MI);
357 CurRange.BeginLabel = Label;
358 CurRange.EndLabel = StateAndEnd->second.second;
359 CurRange.State = StateAndEnd->second.first;
360 break;
361 }
362
363 // If we didn't find a begin label, we are done, return the end iterator.
364 if (!CurRange.BeginLabel) {
365 MBBI = MBBIEnd;
366 return *this;
367 }
368
369 // If this is a begin label, update MBBI to point past the end label.
370 for (; MBBI != MBBIEnd; ++MBBI)
371 if (MBBI->isEHLabel() &&
372 MBBI->getOperand(0).getMCSymbol() == CurRange.EndLabel)
373 break;
374 return *this;
375 }
376
377 /// Utility for making a range for all the invoke ranges.
378 static iterator_range
379 invoke_ranges(WinEHFuncInfo &EHInfo, const MachineBasicBlock &MBB) {
380 return make_range(InvokeLabelIterator(EHInfo, MBB.begin(), MBB.end()),
381 InvokeLabelIterator(EHInfo, MBB.end(), MBB.end()));
283382 }
284383
285384 /// Emit the language-specific data that __C_specific_handler expects. This
311410 /// } Entries[NumEntries];
312411 /// };
313412 void WinException::emitCSpecificHandlerTable(const MachineFunction *MF) {
314 const std::vector &PadInfos = MMI->getLandingPads();
413 auto &OS = *Asm->OutStreamer;
414 MCContext &Ctx = Asm->OutContext;
315415
316416 WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(MF->getFunction());
317 if (!FuncInfo.SEHUnwindMap.empty())
318 report_fatal_error("x64 SEH tables not yet implemented");
417 if (!FuncInfo.SEHUnwindMap.empty()) {
418 // Remember what state we were in the last time we found a begin try label.
419 // This allows us to coalesce many nearby invokes with the same state into
420 // one entry.
421 int LastEHState = -1;
422 MCSymbol *LastBeginLabel = nullptr;
423 MCSymbol *LastEndLabel = nullptr;
424
425 // Use the assembler to compute the number of table entries through label
426 // difference and division.
427 MCSymbol *TableBegin = Ctx.createTempSymbol("lsda_begin");
428 MCSymbol *TableEnd = Ctx.createTempSymbol("lsda_end");
429 const MCExpr *LabelDiff =
430 MCBinaryExpr::createSub(MCSymbolRefExpr::create(TableEnd, Ctx),
431 MCSymbolRefExpr::create(TableBegin, Ctx), Ctx);
432 const MCExpr *EntrySize = MCConstantExpr::create(16, Ctx);
433 const MCExpr *EntryCount =
434 MCBinaryExpr::createDiv(LabelDiff, EntrySize, Ctx);
435 OS.EmitValue(EntryCount, 4);
436
437 OS.EmitLabel(TableBegin);
438
439 // Iterate over all the invoke try ranges. Unlike MSVC, LLVM currently only
440 // models exceptions from invokes. LLVM also allows arbitrary reordering of
441 // the code, so our tables end up looking a bit different. Rather than
442 // trying to match MSVC's tables exactly, we emit a denormalized table. For
443 // each range of invokes in the same state, we emit table entries for all
444 // the actions that would be taken in that state. This means our tables are
445 // slightly bigger, which is OK.
446 for (const auto &MBB : *MF) {
447 for (InvokeRange &I : invoke_ranges(FuncInfo, MBB)) {
448 // If this invoke is in the same state as the last invoke and there were
449 // no non-throwing calls between it, extend the range to include both
450 // and continue.
451 if (!I.SawPotentiallyThrowing && I.State == LastEHState) {
452 LastEndLabel = I.EndLabel;
453 continue;
454 }
455
456 // If this invoke ends a previous one, emit all the actions for this
457 // state.
458 if (LastEHState != -1) {
459 assert(LastBeginLabel && LastEndLabel);
460 for (int State = LastEHState; State != -1;) {
461 SEHUnwindMapEntry &UME = FuncInfo.SEHUnwindMap[State];
462 const MCExpr *FilterOrFinally;
463 const MCExpr *ExceptOrNull;
464 auto *Handler = UME.Handler.get();
465 if (UME.IsFinally) {
466 FilterOrFinally = create32bitRef(Handler->getSymbol());
467 ExceptOrNull = MCConstantExpr::create(0, Ctx);
468 } else {
469 // For an except, the filter can be 1 (catch-all) or a function
470 // label.
471 FilterOrFinally = UME.Filter ? create32bitRef(UME.Filter)
472 : MCConstantExpr::create(1, Ctx);
473 ExceptOrNull = create32bitRef(Handler->getSymbol());
474 }
475
476 OS.EmitValue(getLabelPlusOne(LastBeginLabel), 4);
477 OS.EmitValue(getLabelPlusOne(LastEndLabel), 4);
478 OS.EmitValue(FilterOrFinally, 4);
479 OS.EmitValue(ExceptOrNull, 4);
480
481 State = UME.ToState;
482 }
483 }
484
485 LastBeginLabel = I.BeginLabel;
486 LastEndLabel = I.EndLabel;
487 LastEHState = I.State;
488 }
489 }
490 OS.EmitLabel(TableEnd);
491 return;
492 }
319493
320494 // Simplifying assumptions for first implementation:
321495 // - Cleanups are not implemented.
323497
324498 // The Itanium LSDA table sorts similar landing pads together to simplify the
325499 // actions table, but we don't need that.
500 const std::vector &PadInfos = MMI->getLandingPads();
326501 SmallVector LandingPads;
327502 LandingPads.reserve(PadInfos.size());
328503 for (const auto &LP : PadInfos)
345520 continue; // Ignore gaps.
346521 NumEntries += CSE.LPad->SEHHandlers.size();
347522 }
348 Asm->OutStreamer->EmitIntValue(NumEntries, 4);
523 OS.EmitIntValue(NumEntries, 4);
349524
350525 // If there are no actions, we don't need to iterate again.
351526 if (NumEntries == 0)
376551
377552 // Emit an entry for each action.
378553 for (SEHHandler Handler : LPad->SEHHandlers) {
379 Asm->OutStreamer->EmitValue(Begin, 4);
380 Asm->OutStreamer->EmitValue(End, 4);
554 OS.EmitValue(Begin, 4);
555 OS.EmitValue(End, 4);
381556
382557 // Emit the filter or finally function pointer, if present. Otherwise,
383558 // emit '1' to indicate a catch-all.
384559 const Function *F = Handler.FilterOrFinally;
385560 if (F)
386 Asm->OutStreamer->EmitValue(create32bitRef(Asm->getSymbol(F)), 4);
561 OS.EmitValue(create32bitRef(Asm->getSymbol(F)), 4);
387562 else
388 Asm->OutStreamer->EmitIntValue(1, 4);
563 OS.EmitIntValue(1, 4);
389564
390565 // Emit the recovery address, if present. Otherwise, this must be a
391566 // finally.
392567 const BlockAddress *BA = Handler.RecoverBA;
393568 if (BA)
394 Asm->OutStreamer->EmitValue(
569 OS.EmitValue(
395570 create32bitRef(Asm->GetBlockAddressSymbol(BA)), 4);
396571 else
397 Asm->OutStreamer->EmitIntValue(0, 4);
572 OS.EmitIntValue(0, 4);
398573 }
399574 }
400575 }
582757 void WinException::computeIP2StateTable(
583758 const MachineFunction *MF, WinEHFuncInfo &FuncInfo,
584759 SmallVectorImpl> &IPToStateTable) {
585 // Whether there is a potentially throwing instruction (currently this means
586 // an ordinary call) between the end of the previous try-range and now.
587 bool SawPotentiallyThrowing = true;
588
589760 // Remember what state we were in the last time we found a begin try label.
590761 // This allows us to coalesce many nearby invokes with the same state into one
591762 // entry.
601772 for (const auto &MBB : *MF) {
602773 // FIXME: Do we need to emit entries for funclet base states?
603774
604 for (const auto &MI : MBB) {
605 // Find all the EH_LABEL instructions, tracking if we've crossed a
606 // potentially throwing call since the last label.
607 if (!MI.isEHLabel()) {
608 if (MI.isCall())
609 SawPotentiallyThrowing |= !callToNoUnwindFunction(&MI);
610 continue;
611 }
612
613 // If this was an end label, return SawPotentiallyThrowing to the start
614 // state and keep going. Otherwise, we will consider the call between the
615 // begin/end labels to be a potentially throwing call and generate extra
616 // table entries.
617 MCSymbol *Label = MI.getOperand(0).getMCSymbol();
618 if (Label == LastEndLabel)
619 SawPotentiallyThrowing = false;
620
621 // Check if this was a begin label. Otherwise, it must be an end label or
622 // some random label, and we should continue.
623 auto StateAndEnd = FuncInfo.InvokeToStateMap.find(Label);
624 if (StateAndEnd == FuncInfo.InvokeToStateMap.end())
625 continue;
626
627 // Extract the state and end label.
628 int State;
629 MCSymbol *EndLabel;
630 std::tie(State, EndLabel) = StateAndEnd->second;
631
775 for (InvokeRange &I : invoke_ranges(FuncInfo, MBB)) {
776 assert(I.BeginLabel && I.EndLabel);
632777 // If there was a potentially throwing call between this begin label and
633778 // the last end label, we need an extra base state entry to indicate that
634779 // those calls unwind directly to the caller.
635 if (SawPotentiallyThrowing && LastEHState != -1) {
780 if (I.SawPotentiallyThrowing && LastEHState != -1) {
636781 IPToStateTable.push_back(
637782 std::make_pair(getLabelPlusOne(LastEndLabel), -1));
638 SawPotentiallyThrowing = false;
639783 LastEHState = -1;
640784 }
641785
642786 // Emit an entry indicating that PCs after 'Label' have this EH state.
643 if (State != LastEHState)
644 IPToStateTable.push_back(std::make_pair(create32bitRef(Label), State));
645 LastEHState = State;
646 LastEndLabel = EndLabel;
787 if (I.State != LastEHState)
788 IPToStateTable.push_back(
789 std::make_pair(create32bitRef(I.BeginLabel), I.State));
790 LastEHState = I.State;
791 LastEndLabel = I.EndLabel;
647792 }
648793 }
649794
27232723 }
27242724 }
27252725
2726 static int addSEHHandler(WinEHFuncInfo &FuncInfo, int ParentState,
2727 const Function *Filter, const BasicBlock *Handler) {
2726 static int addSEHExcept(WinEHFuncInfo &FuncInfo, int ParentState,
2727 const Function *Filter, const BasicBlock *Handler) {
27282728 SEHUnwindMapEntry Entry;
27292729 Entry.ToState = ParentState;
2730 Entry.IsFinally = false;
27302731 Entry.Filter = Filter;
2732 Entry.Handler = Handler;
2733 FuncInfo.SEHUnwindMap.push_back(Entry);
2734 return FuncInfo.SEHUnwindMap.size() - 1;
2735 }
2736
2737 static int addSEHFinally(WinEHFuncInfo &FuncInfo, int ParentState,
2738 const BasicBlock *Handler) {
2739 SEHUnwindMapEntry Entry;
2740 Entry.ToState = ParentState;
2741 Entry.IsFinally = true;
2742 Entry.Filter = nullptr;
27312743 Entry.Handler = Handler;
27322744 FuncInfo.SEHUnwindMap.push_back(Entry);
27332745 return FuncInfo.SEHUnwindMap.size() - 1;
27522764 "SEH doesn't have multiple handlers per __try");
27532765 const CatchPadInst *CPI = Handlers.front();
27542766 const BasicBlock *CatchPadBB = CPI->getParent();
2755 const Function *Filter =
2756 cast(CPI->getArgOperand(0)->stripPointerCasts());
2767 const Constant *FilterOrNull =
2768 cast(CPI->getArgOperand(0)->stripPointerCasts());
2769 const Function *Filter = dyn_cast(FilterOrNull);
2770 assert((Filter || FilterOrNull->isNullValue()) &&
2771 "unexpected filter value");
27572772 int TryState =
2758 addSEHHandler(FuncInfo, ParentState, Filter, CPI->getNormalDest());
2773 addSEHExcept(FuncInfo, ParentState, Filter, CPI->getNormalDest());
27592774
27602775 // Everything in the __try block uses TryState as its parent state.
27612776 FuncInfo.EHPadStateMap[CPI] = TryState;
27742789 if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
27752790 calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, ParentState);
27762791 } else if (isa(FirstNonPHI)) {
2777 int CleanupState =
2778 addSEHHandler(FuncInfo, ParentState, /*Filter=*/nullptr, &BB);
2792 int CleanupState = addSEHFinally(FuncInfo, ParentState, &BB);
27792793 FuncInfo.EHPadStateMap[FirstNonPHI] = CleanupState;
27802794 DEBUG(dbgs() << "Assigning state #" << CleanupState << " to BB "
27812795 << BB.getName() << '\n');
14881488 if (CSI.empty())
14891489 return false;
14901490
1491 // Don't restore CSRs in 32-bit EH funclets. Matches
1492 // spillCalleeSavedRegisters.
1493 if (isFuncletReturnInstr(MI) && STI.is32Bit() && STI.isOSWindows())
1494 return true;
1491 if (isFuncletReturnInstr(MI) && STI.isOSWindows()) {
1492 // Don't restore CSRs in 32-bit EH funclets. Matches
1493 // spillCalleeSavedRegisters.
1494 if (STI.is32Bit())
1495 return true;
1496 // Don't restore CSRs before an SEH catchret. SEH except blocks do not form
1497 // funclets. emitEpilogue transforms these to normal jumps.
1498 if (MI->getOpcode() == X86::CATCHRET) {
1499 const Function *Func = MBB.getParent()->getFunction();
1500 bool IsSEH = isAsynchronousEHPersonality(
1501 classifyEHPersonality(Func->getPersonalityFn()));
1502 if (IsSEH)
1503 return true;
1504 }
1505 }
14951506
14961507 DebugLoc DL = MBB.findDebugLoc(MI);
14971508
0 ; RUN: llc < %s | FileCheck %s
1
2 ; Based on the source:
3 ; extern "C" int puts(const char *);
4 ; extern "C" int printf(const char *, ...);
5 ; extern "C" int do_div(int a, int b) { return a / b; }
6 ; extern "C" int filt();
7 ; int main() {
8 ; __try {
9 ; __try {
10 ; do_div(1, 0);
11 ; } __except (1) {
12 ; __try {
13 ; do_div(1, 0);
14 ; } __finally {
15 ; puts("finally");
16 ; }
17 ; }
18 ; } __except (filt()) {
19 ; puts("caught");
20 ; }
21 ; return 0;
22 ; }
23
24 ; ModuleID = 't.cpp'
25 target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
26 target triple = "x86_64-pc-windows-msvc"
27
28 $"\01??_C@_07MKBLAIAL@finally?$AA@" = comdat any
29
30 $"\01??_C@_06IBDBCMGJ@caught?$AA@" = comdat any
31
32 @"\01??_C@_07MKBLAIAL@finally?$AA@" = linkonce_odr unnamed_addr constant [8 x i8] c"finally\00", comdat, align 1
33 @"\01??_C@_06IBDBCMGJ@caught?$AA@" = linkonce_odr unnamed_addr constant [7 x i8] c"caught\00", comdat, align 1
34
35 ; Function Attrs: nounwind readnone
36 define i32 @do_div(i32 %a, i32 %b) #0 {
37 entry:
38 %div = sdiv i32 %a, %b
39 ret i32 %div
40 }
41
42 define i32 @main() #1 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) {
43 entry:
44 %call = invoke i32 @do_div(i32 1, i32 0) #4
45 to label %__try.cont.12 unwind label %catch.dispatch
46
47 catch.dispatch: ; preds = %entry
48 %0 = catchpad [i8* null]
49 to label %__except unwind label %catchendblock
50
51 __except: ; preds = %catch.dispatch
52 catchret %0 to label %__except.2
53
54 __except.2: ; preds = %__except
55 %call4 = invoke i32 @do_div(i32 1, i32 0) #4
56 to label %invoke.cont.3 unwind label %ehcleanup
57
58 invoke.cont.3: ; preds = %__except.2
59 invoke fastcc void @"\01?fin$0@0@main@@"() #4
60 to label %__try.cont.12 unwind label %catch.dispatch.7
61
62 catchendblock: ; preds = %catch.dispatch
63 catchendpad unwind label %catch.dispatch.7
64
65 ehcleanup: ; preds = %__except.2
66 %1 = cleanuppad []
67 invoke fastcc void @"\01?fin$0@0@main@@"() #4
68 to label %invoke.cont.6 unwind label %ehcleanup.end
69
70 invoke.cont.6: ; preds = %ehcleanup
71 cleanupret %1 unwind label %catch.dispatch.7
72
73 catch.dispatch.7: ; preds = %invoke.cont.3, %invoke.cont.6, %ehcleanup.end, %catchendblock
74 %2 = catchpad [i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0@0@main@@" to i8*)]
75 to label %__except.ret unwind label %catchendblock.8
76
77 __except.ret: ; preds = %catch.dispatch.7
78 catchret %2 to label %__except.9
79
80 __except.9: ; preds = %__except.ret
81 %call11 = tail call i32 @puts(i8* nonnull getelementptr inbounds ([7 x i8], [7 x i8]* @"\01??_C@_06IBDBCMGJ@caught?$AA@", i64 0, i64 0))
82 br label %__try.cont.12
83
84 __try.cont.12: ; preds = %invoke.cont.3, %entry, %__except.9
85 ret i32 0
86
87 catchendblock.8: ; preds = %catch.dispatch.7
88 catchendpad unwind to caller
89
90 ehcleanup.end: ; preds = %ehcleanup
91 cleanupendpad %1 unwind label %catch.dispatch.7
92 }
93
94 ; CHECK: main: # @main
95 ; CHECK: .seh_proc main
96 ; CHECK: .seh_handler __C_specific_handler, @unwind, @except
97 ; CHECK: pushq %rbp
98 ; CHECK: .seh_pushreg 5
99 ; CHECK: subq $48, %rsp
100 ; CHECK: .seh_stackalloc 48
101 ; CHECK: leaq 48(%rsp), %rbp
102 ; CHECK: .seh_setframe 5, 48
103 ; CHECK: .seh_endprologue
104 ; CHECK: .Ltmp0:
105 ; CHECK: movl $1, %ecx
106 ; CHECK: xorl %edx, %edx
107 ; CHECK: callq do_div
108 ; CHECK: .Ltmp1:
109 ; CHECK: .LBB1_[[epilogue:[0-9]+]]: # %__try.cont.12
110 ; CHECK: xorl %eax, %eax
111 ; CHECK: addq $48, %rsp
112 ; CHECK: popq %rbp
113 ; CHECK: retq
114 ; CHECK: .LBB1_[[except1bb:[0-9]+]]: # %__except
115 ; CHECK: .Ltmp2:
116 ; CHECK: movl $1, %ecx
117 ; CHECK: xorl %edx, %edx
118 ; CHECK: callq do_div
119 ; CHECK: .Ltmp3:
120 ; CHECK: callq "?fin$0@0@main@@"
121 ; CHECK: jmp .LBB1_[[epilogue]]
122 ; CHECK: .LBB1_[[except2bb:[0-9]+]]: # %__except.ret
123 ; CHECK: leaq "??_C@_06IBDBCMGJ@caught?$AA@"(%rip), %rcx
124 ; CHECK: callq puts
125 ; CHECK: jmp .LBB1_[[epilogue]]
126
127 ; CHECK: .seh_handlerdata
128 ; CHECK-NEXT: .long (.Ltmp14-.Ltmp13)/16
129 ; CHECK-NEXT: .Ltmp13:
130 ; CHECK-NEXT: .long .Ltmp0@IMGREL
131 ; CHECK-NEXT: .long .Ltmp1@IMGREL+1
132 ; CHECK-NEXT: .long 1
133 ; CHECK-NEXT: .long .LBB1_[[except1bb]]@IMGREL
134 ; CHECK-NEXT: .long .Ltmp0@IMGREL
135 ; CHECK-NEXT: .long .Ltmp1@IMGREL+1
136 ; CHECK-NEXT: .long "?filt$0@0@main@@"@IMGREL
137 ; CHECK-NEXT: .long .LBB1_[[except2bb]]@IMGREL
138 ; CHECK-NEXT: .long .Ltmp2@IMGREL
139 ; CHECK-NEXT: .long .Ltmp3@IMGREL+1
140 ; CHECK-NEXT: .long .LBB1_[[finbb:[0-9]+]]@IMGREL
141 ; CHECK-NEXT: .long 0
142 ; CHECK-NEXT: .long .Ltmp2@IMGREL
143 ; CHECK-NEXT: .long .Ltmp3@IMGREL+1
144 ; CHECK-NEXT: .long "?filt$0@0@main@@"@IMGREL
145 ; CHECK-NEXT: .long .LBB1_6@IMGREL
146 ; CHECK-NEXT: .Ltmp14:
147
148 ; CHECK: .text
149 ; CHECK: .seh_endproc
150
151 ; CHECK: "?dtor$4@?0?main@4HA":
152 ; CHECK: .seh_proc "?dtor$4@?0?main@4HA"
153 ; CHECK: .seh_handler __C_specific_handler, @unwind, @except
154 ; CHECK: .LBB1_[[finbb]]: # %ehcleanup
155 ; CHECK: movq %rdx, 16(%rsp)
156 ; CHECK: pushq %rbp
157 ; CHECK: .seh_pushreg 5
158 ; CHECK: subq $32, %rsp
159 ; CHECK: .seh_stackalloc 32
160 ; CHECK: leaq 48(%rdx), %rbp
161 ; CHECK: .seh_endprologue
162 ; CHECK: callq "?fin$0@0@main@@"
163 ; CHECK: nop
164 ; CHECK: addq $32, %rsp
165 ; CHECK: popq %rbp
166 ; CHECK: retq
167 ; CHECK: .seh_handlerdata
168 ; CHECK: .seh_endproc
169
170 define internal i32 @"\01?filt$0@0@main@@"(i8* nocapture readnone %exception_pointers, i8* nocapture readnone %frame_pointer) #1 {
171 entry:
172 %call = tail call i32 @filt()
173 ret i32 %call
174 }
175
176 ; CHECK: "?filt$0@0@main@@": # @"\01?filt$0@0@main@@"
177 ; CHECK: .seh_proc "?filt$0@0@main@@"
178 ; CHECK: .seh_endprologue
179 ; CHECK: rex64 jmp filt # TAILCALL
180 ; CHECK: .seh_handlerdata
181
182 declare i32 @filt() #1
183
184 declare i32 @__C_specific_handler(...)
185
186 ; Function Attrs: noinline nounwind
187 define internal fastcc void @"\01?fin$0@0@main@@"() #2 {
188 entry:
189 %call = tail call i32 @puts(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @"\01??_C@_07MKBLAIAL@finally?$AA@", i64 0, i64 0)) #5
190 ret void
191 }
192
193 ; Function Attrs: nounwind
194 declare i32 @puts(i8* nocapture readonly) #3
195
196 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" }
197 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" }
198 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" }
199 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" }
200 attributes #4 = { noinline }
201 attributes #5 = { nounwind }