llvm.org GIT mirror llvm / 436444d
[WinEH] Rip out the landingpad-based C++ EH state numbering code It never really worked, and the new code is working better every day. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@247860 91177308-0d34-0410-b5e6-96231b3b80d8 Reid Kleckner 4 years ago
15 changed file(s) with 77 addition(s) and 1576 deletion(s). Raw diff Collapse all Expand all
158158 };
159159
160160 struct WinEHFuncInfo {
161 DenseMap RootLPad;
162 DenseMap LastInvoke;
163 DenseMap HandlerEnclosedState;
164 DenseMap LastInvokeVisited;
165161 DenseMap EHPadStateMap;
166 DenseMap CatchHandlerParentFrameObjIdx;
167 DenseMap CatchHandlerParentFrameObjOffset;
168 DenseMap CatchHandlerMaxState;
169 DenseMap HandlerBaseState;
170162 SmallVector UnwindMap;
171163 SmallVector TryBlockMap;
172164 SmallVector SEHUnwindMap;
173165 SmallVector, 4> IPToStateList;
174166 int UnwindHelpFrameIdx = INT_MAX;
175167 int UnwindHelpFrameOffset = -1;
176 unsigned NumIPToStateFuncsVisited = 0;
177168
178169 int getLastStateNumber() const { return UnwindMap.size() - 1; }
179170
9595 hasEHFunclets || (F->hasFnAttribute("wineh-parent") && F == ParentF);
9696 shouldEmitPersonality = false;
9797 return;
98 }
99
100 // If this was an outlined handler, we need to define the label corresponding
101 // to the offset of the parent frame relative to the stack pointer after the
102 // prologue.
103 if (F != ParentF) {
104 WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF);
105 auto I = FuncInfo.CatchHandlerParentFrameObjOffset.find(F);
106 if (I != FuncInfo.CatchHandlerParentFrameObjOffset.end()) {
107 MCSymbol *HandlerTypeParentFrameOffset =
108 Asm->OutContext.getOrCreateParentFrameOffsetSymbol(
109 GlobalValue::getRealLinkageName(F->getName()));
110
111 // Emit a symbol assignment.
112 Asm->OutStreamer->EmitAssignment(
113 HandlerTypeParentFrameOffset,
114 MCConstantExpr::create(I->second, Asm->OutContext));
115 }
11698 }
11799
118100 if (shouldEmitMoves || shouldEmitPersonality)
324306
325307 void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
326308 const Function *F = MF->getFunction();
327 const Function *ParentF = MMI->getWinEHParent(F);
328309 auto &OS = *Asm->OutStreamer;
329 WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF);
330
331 StringRef ParentLinkageName =
332 GlobalValue::getRealLinkageName(ParentF->getName());
310 WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(F);
311
312 StringRef FuncLinkageName = GlobalValue::getRealLinkageName(F->getName());
333313
334314 MCSymbol *FuncInfoXData = nullptr;
335315 if (shouldEmitPersonality) {
336 FuncInfoXData = Asm->OutContext.getOrCreateSymbol(
337 Twine("$cppxdata$", ParentLinkageName));
316 FuncInfoXData =
317 Asm->OutContext.getOrCreateSymbol(Twine("$cppxdata$", FuncLinkageName));
338318 OS.EmitValue(create32bitRef(FuncInfoXData), 4);
339319
340 extendIP2StateTable(MF, ParentF, FuncInfo);
341
342 if (!MMI->hasEHFunclets()) {
343 // Defer emission until we've visited the parent function and all the
344 // catch handlers. Cleanups don't contribute to the ip2state table, so
345 // don't count them.
346 if (ParentF != F && !FuncInfo.CatchHandlerMaxState.count(F))
347 return;
348 ++FuncInfo.NumIPToStateFuncsVisited;
349 if (FuncInfo.NumIPToStateFuncsVisited !=
350 FuncInfo.CatchHandlerMaxState.size())
351 return;
352 }
320 extendIP2StateTable(MF, FuncInfo);
353321 } else {
354 FuncInfoXData = Asm->OutContext.getOrCreateLSDASymbol(ParentLinkageName);
355 emitEHRegistrationOffsetLabel(FuncInfo, ParentLinkageName);
322 FuncInfoXData = Asm->OutContext.getOrCreateLSDASymbol(FuncLinkageName);
323 emitEHRegistrationOffsetLabel(FuncInfo, FuncLinkageName);
356324 }
357325
358326 MCSymbol *UnwindMapXData = nullptr;
360328 MCSymbol *IPToStateXData = nullptr;
361329 if (!FuncInfo.UnwindMap.empty())
362330 UnwindMapXData = Asm->OutContext.getOrCreateSymbol(
363 Twine("$stateUnwindMap$", ParentLinkageName));
331 Twine("$stateUnwindMap$", FuncLinkageName));
364332 if (!FuncInfo.TryBlockMap.empty())
365 TryBlockMapXData = Asm->OutContext.getOrCreateSymbol(
366 Twine("$tryMap$", ParentLinkageName));
333 TryBlockMapXData =
334 Asm->OutContext.getOrCreateSymbol(Twine("$tryMap$", FuncLinkageName));
367335 if (!FuncInfo.IPToStateList.empty())
368 IPToStateXData = Asm->OutContext.getOrCreateSymbol(
369 Twine("$ip2state$", ParentLinkageName));
336 IPToStateXData =
337 Asm->OutContext.getOrCreateSymbol(Twine("$ip2state$", FuncLinkageName));
370338
371339 // FuncInfo {
372340 // uint32_t MagicNumber
422390 SmallVector HandlerMaps;
423391 for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) {
424392 WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I];
393
425394 MCSymbol *HandlerMapXData = nullptr;
426
427395 if (!TBME.HandlerArray.empty())
428396 HandlerMapXData =
429397 Asm->OutContext.getOrCreateSymbol(Twine("$handlerMap$")
430398 .concat(Twine(I))
431399 .concat("$")
432 .concat(ParentLinkageName));
433
400 .concat(FuncLinkageName));
434401 HandlerMaps.push_back(HandlerMapXData);
435402
436 int CatchHigh = TBME.CatchHigh;
437 if (CatchHigh == -1) {
438 for (WinEHHandlerType &HT : TBME.HandlerArray)
439 CatchHigh =
440 std::max(CatchHigh, FuncInfo.CatchHandlerMaxState[cast(
441 HT.Handler.get())]);
442 }
443
444 assert(TBME.TryLow <= TBME.TryHigh);
403 // TBMEs should form intervals.
404 assert(0 <= TBME.TryLow && "bad trymap interval");
405 assert(TBME.TryLow <= TBME.TryHigh && "bad trymap interval");
406 assert(TBME.TryHigh < TBME.CatchHigh && "bad trymap interval");
407 assert(TBME.CatchHigh < int(FuncInfo.UnwindMap.size()) &&
408 "bad trymap interval");
409
445410 OS.EmitIntValue(TBME.TryLow, 4); // TryLow
446411 OS.EmitIntValue(TBME.TryHigh, 4); // TryHigh
447 OS.EmitIntValue(CatchHigh, 4); // CatchHigh
412 OS.EmitIntValue(TBME.CatchHigh, 4); // CatchHigh
448413 OS.EmitIntValue(TBME.HandlerArray.size(), 4); // NumCatches
449414 OS.EmitValue(create32bitRef(HandlerMapXData), 4); // HandlerArray
450415 }
470435 if (HT.CatchObjRecoverIdx >= 0) {
471436 MCSymbol *FrameAllocOffset =
472437 Asm->OutContext.getOrCreateFrameAllocSymbol(
473 GlobalValue::getRealLinkageName(ParentF->getName()),
474 HT.CatchObjRecoverIdx);
438 FuncLinkageName, HT.CatchObjRecoverIdx);
475439 FrameAllocOffsetRef = MCSymbolRefExpr::create(
476440 FrameAllocOffset, MCSymbolRefExpr::VK_None, Asm->OutContext);
477441 } else if (HT.CatchObj.FrameOffset != INT_MAX) {
496460 OS.EmitValue(create32bitRef(HandlerSym), 4); // Handler
497461
498462 if (shouldEmitPersonality) {
499 if (FuncInfo.CatchHandlerParentFrameObjOffset.empty()) {
500 // With the new IR, this is always 16 + 8 + getMaxCallFrameSize().
501 // Keep this in sync with X86FrameLowering::emitPrologue.
502 int ParentFrameOffset =
503 16 + 8 + MF->getFrameInfo()->getMaxCallFrameSize();
504 OS.EmitIntValue(ParentFrameOffset, 4); // ParentFrameOffset
505 } else {
506 MCSymbol *ParentFrameOffset =
507 Asm->OutContext.getOrCreateParentFrameOffsetSymbol(
508 GlobalValue::getRealLinkageName(
509 HT.Handler.get()->getName()));
510 const MCSymbolRefExpr *ParentFrameOffsetRef =
511 MCSymbolRefExpr::create(ParentFrameOffset, Asm->OutContext);
512 OS.EmitValue(ParentFrameOffsetRef, 4); // ParentFrameOffset
513 }
463 // With the new IR, this is always 16 + 8 + getMaxCallFrameSize().
464 // Keep this in sync with X86FrameLowering::emitPrologue.
465 int ParentFrameOffset =
466 16 + 8 + MF->getFrameInfo()->getMaxCallFrameSize();
467 OS.EmitIntValue(ParentFrameOffset, 4); // ParentFrameOffset
514468 }
515469 }
516470 }
530484 }
531485
532486 void WinException::extendIP2StateTable(const MachineFunction *MF,
533 const Function *ParentF,
534487 WinEHFuncInfo &FuncInfo) {
535 const Function *F = MF->getFunction();
536
537488 // The Itanium LSDA table sorts similar landing pads together to simplify the
538489 // actions table, but we don't need that.
539490 SmallVector LandingPads;
559510
560511 // Include ip2state entries for the beginning of the main function and
561512 // for catch handler functions.
562 if (F == ParentF) {
563 FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1));
564 LastEHState = -1;
565 } else if (FuncInfo.HandlerBaseState.count(F)) {
566 FuncInfo.IPToStateList.push_back(
567 std::make_pair(LastLabel, FuncInfo.HandlerBaseState[F]));
568 LastEHState = FuncInfo.HandlerBaseState[F];
569 }
513 FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1));
514 LastEHState = -1;
570515 for (const auto &MBB : *MF) {
571516 for (const auto &MI : MBB) {
572517 if (!MI.isEHLabel()) {
4646 /// tables.
4747 void emitExceptHandlerTable(const MachineFunction *MF);
4848
49 void extendIP2StateTable(const MachineFunction *MF, const Function *ParentF,
50 WinEHFuncInfo &FuncInfo);
49 void extendIP2StateTable(const MachineFunction *MF, WinEHFuncInfo &FuncInfo);
5150
5251 /// Emits the label used with llvm.x86.seh.recoverfp, which is used by
5352 /// outlined funclets.
828828 TFI.getFrameIndexReference(Fn, H.CatchObj.FrameIndex, UnusedReg);
829829 }
830830 }
831 } else if (MMI.hasWinEHFuncInfo(F)) {
832 WinEHFuncInfo &FuncInfo = MMI.getWinEHFuncInfo(Fn.getFunction());
833 auto I = FuncInfo.CatchHandlerParentFrameObjIdx.find(F);
834 if (I != FuncInfo.CatchHandlerParentFrameObjIdx.end())
835 FuncInfo.CatchHandlerParentFrameObjOffset[F] =
836 TFI.getFrameIndexReferenceFromSP(Fn, I->second, FrameReg);
837831 }
838832
839833 // Store SPAdj at exit of a basic block.
25752575 std::reverse(Actions.begin(), Actions.end());
25762576 }
25772577
2578 namespace {
2579 struct WinEHNumbering {
2580 WinEHNumbering(WinEHFuncInfo &FuncInfo) : FuncInfo(FuncInfo),
2581 CurrentBaseState(-1), NextState(0) {}
2582
2583 WinEHFuncInfo &FuncInfo;
2584 int CurrentBaseState;
2585 int NextState;
2586
2587 SmallVector, 4> HandlerStack;
2588 SmallPtrSet VisitedHandlers;
2589
2590 int currentEHNumber() const {
2591 return HandlerStack.empty() ? CurrentBaseState : HandlerStack.back()->getEHState();
2592 }
2593
2594 void createUnwindMapEntry(int ToState, ActionHandler *AH);
2595 void createTryBlockMapEntry(int TryLow, int TryHigh,
2596 ArrayRef Handlers);
2597 void processCallSite(MutableArrayRef> Actions,
2598 ImmutableCallSite CS);
2599 void popUnmatchedActions(int FirstMismatch);
2600 void calculateStateNumbers(const Function &F);
2601 void findActionRootLPads(const Function &F);
2602 };
2603 }
2604
26052578 static int addUnwindMapEntry(WinEHFuncInfo &FuncInfo, int ToState,
26062579 const Value *V) {
26072580 WinEHUnwindMapEntry UME;
26362609 TBME.HandlerArray.push_back(HT);
26372610 }
26382611 FuncInfo.TryBlockMap.push_back(TBME);
2639 }
2640
2641 void WinEHNumbering::createUnwindMapEntry(int ToState, ActionHandler *AH) {
2642 Value *V = nullptr;
2643 if (auto *CH = dyn_cast_or_null(AH))
2644 V = cast(CH->getHandlerBlockOrFunc());
2645 addUnwindMapEntry(FuncInfo, ToState, V);
2646 }
2647
2648 void WinEHNumbering::createTryBlockMapEntry(int TryLow, int TryHigh,
2649 ArrayRef Handlers) {
2650 // See if we already have an entry for this set of handlers.
2651 // This is using iterators rather than a range-based for loop because
2652 // if we find the entry we're looking for we'll need the iterator to erase it.
2653 int NumHandlers = Handlers.size();
2654 auto I = FuncInfo.TryBlockMap.begin();
2655 auto E = FuncInfo.TryBlockMap.end();
2656 for ( ; I != E; ++I) {
2657 auto &Entry = *I;
2658 if (Entry.HandlerArray.size() != (size_t)NumHandlers)
2659 continue;
2660 int N;
2661 for (N = 0; N < NumHandlers; ++N) {
2662 if (Entry.HandlerArray[N].Handler.get() !=
2663 Handlers[N]->getHandlerBlockOrFunc())
2664 break; // breaks out of inner loop
2665 }
2666 // If all the handlers match, this is what we were looking for.
2667 if (N == NumHandlers) {
2668 break;
2669 }
2670 }
2671
2672 // If we found an existing entry for this set of handlers, extend the range
2673 // but move the entry to the end of the map vector. The order of entries
2674 // in the map is critical to the way that the runtime finds handlers.
2675 // FIXME: Depending on what has happened with block ordering, this may
2676 // incorrectly combine entries that should remain separate.
2677 if (I != E) {
2678 // Copy the existing entry.
2679 WinEHTryBlockMapEntry Entry = *I;
2680 Entry.TryLow = std::min(TryLow, Entry.TryLow);
2681 Entry.TryHigh = std::max(TryHigh, Entry.TryHigh);
2682 assert(Entry.TryLow <= Entry.TryHigh);
2683 // Erase the old entry and add this one to the back.
2684 FuncInfo.TryBlockMap.erase(I);
2685 FuncInfo.TryBlockMap.push_back(Entry);
2686 return;
2687 }
2688
2689 // If we didn't find an entry, create a new one.
2690 WinEHTryBlockMapEntry TBME;
2691 TBME.TryLow = TryLow;
2692 TBME.TryHigh = TryHigh;
2693 assert(TBME.TryLow <= TBME.TryHigh);
2694 for (CatchHandler *CH : Handlers) {
2695 WinEHHandlerType HT;
2696 if (CH->getSelector()->isNullValue()) {
2697 HT.Adjectives = 0x40;
2698 HT.TypeDescriptor = nullptr;
2699 } else {
2700 auto *GV = cast(CH->getSelector()->stripPointerCasts());
2701 // Selectors are always pointers to GlobalVariables with 'struct' type.
2702 // The struct has two fields, adjectives and a type descriptor.
2703 auto *CS = cast(GV->getInitializer());
2704 HT.Adjectives =
2705 cast(CS->getAggregateElement(0U))->getZExtValue();
2706 HT.TypeDescriptor =
2707 cast(CS->getAggregateElement(1)->stripPointerCasts());
2708 }
2709 HT.Handler = cast(CH->getHandlerBlockOrFunc());
2710 HT.CatchObjRecoverIdx = CH->getExceptionVarIndex();
2711 HT.CatchObj.Alloca = nullptr;
2712 TBME.HandlerArray.push_back(HT);
2713 }
2714 FuncInfo.TryBlockMap.push_back(TBME);
2715 }
2716
2717 static void print_name(const Value *V) {
2718 #ifndef NDEBUG
2719 if (!V) {
2720 DEBUG(dbgs() << "null");
2721 return;
2722 }
2723
2724 if (const auto *F = dyn_cast(V))
2725 DEBUG(dbgs() << F->getName());
2726 else
2727 DEBUG(V->dump());
2728 #endif
2729 }
2730
2731 void WinEHNumbering::processCallSite(
2732 MutableArrayRef> Actions,
2733 ImmutableCallSite CS) {
2734 DEBUG(dbgs() << "processCallSite (EH state = " << currentEHNumber()
2735 << ") for: ");
2736 print_name(CS ? CS.getCalledValue() : nullptr);
2737 DEBUG(dbgs() << '\n');
2738
2739 DEBUG(dbgs() << "HandlerStack: \n");
2740 for (int I = 0, E = HandlerStack.size(); I < E; ++I) {
2741 DEBUG(dbgs() << " ");
2742 print_name(HandlerStack[I]->getHandlerBlockOrFunc());
2743 DEBUG(dbgs() << '\n');
2744 }
2745 DEBUG(dbgs() << "Actions: \n");
2746 for (int I = 0, E = Actions.size(); I < E; ++I) {
2747 DEBUG(dbgs() << " ");
2748 print_name(Actions[I]->getHandlerBlockOrFunc());
2749 DEBUG(dbgs() << '\n');
2750 }
2751 int FirstMismatch = 0;
2752 for (int E = std::min(HandlerStack.size(), Actions.size()); FirstMismatch < E;
2753 ++FirstMismatch) {
2754 if (HandlerStack[FirstMismatch]->getHandlerBlockOrFunc() !=
2755 Actions[FirstMismatch]->getHandlerBlockOrFunc())
2756 break;
2757 }
2758
2759 // Remove unmatched actions from the stack and process their EH states.
2760 popUnmatchedActions(FirstMismatch);
2761
2762 DEBUG(dbgs() << "Pushing actions for CallSite: ");
2763 print_name(CS ? CS.getCalledValue() : nullptr);
2764 DEBUG(dbgs() << '\n');
2765
2766 bool LastActionWasCatch = false;
2767 const LandingPadInst *LastRootLPad = nullptr;
2768 for (size_t I = FirstMismatch; I != Actions.size(); ++I) {
2769 // We can reuse eh states when pushing two catches for the same invoke.
2770 bool CurrActionIsCatch = isa(Actions[I].get());
2771 auto *Handler = cast(Actions[I]->getHandlerBlockOrFunc());
2772 // Various conditions can lead to a handler being popped from the
2773 // stack and re-pushed later. That shouldn't create a new state.
2774 // FIXME: Can code optimization lead to re-used handlers?
2775 if (FuncInfo.HandlerEnclosedState.count(Handler)) {
2776 // If we already assigned the state enclosed by this handler re-use it.
2777 Actions[I]->setEHState(FuncInfo.HandlerEnclosedState[Handler]);
2778 continue;
2779 }
2780 const LandingPadInst* RootLPad = FuncInfo.RootLPad[Handler];
2781 if (CurrActionIsCatch && LastActionWasCatch && RootLPad == LastRootLPad) {
2782 DEBUG(dbgs() << "setEHState for handler to " << currentEHNumber() << "\n");
2783 Actions[I]->setEHState(currentEHNumber());
2784 } else {
2785 DEBUG(dbgs() << "createUnwindMapEntry(" << currentEHNumber() << ", ");
2786 print_name(Actions[I]->getHandlerBlockOrFunc());
2787 DEBUG(dbgs() << ") with EH state " << NextState << "\n");
2788 createUnwindMapEntry(currentEHNumber(), Actions[I].get());
2789 DEBUG(dbgs() << "setEHState for handler to " << NextState << "\n");
2790 Actions[I]->setEHState(NextState);
2791 NextState++;
2792 }
2793 HandlerStack.push_back(std::move(Actions[I]));
2794 LastActionWasCatch = CurrActionIsCatch;
2795 LastRootLPad = RootLPad;
2796 }
2797
2798 // This is used to defer numbering states for a handler until after the
2799 // last time it appears in an invoke action list.
2800 if (CS.isInvoke()) {
2801 for (int I = 0, E = HandlerStack.size(); I < E; ++I) {
2802 auto *Handler = cast(HandlerStack[I]->getHandlerBlockOrFunc());
2803 if (FuncInfo.LastInvoke[Handler] != cast(CS.getInstruction()))
2804 continue;
2805 FuncInfo.LastInvokeVisited[Handler] = true;
2806 DEBUG(dbgs() << "Last invoke of ");
2807 print_name(Handler);
2808 DEBUG(dbgs() << " has been visited.\n");
2809 }
2810 }
2811
2812 DEBUG(dbgs() << "In EHState " << currentEHNumber() << " for CallSite: ");
2813 print_name(CS ? CS.getCalledValue() : nullptr);
2814 DEBUG(dbgs() << '\n');
2815 }
2816
2817 void WinEHNumbering::popUnmatchedActions(int FirstMismatch) {
2818 // Don't recurse while we are looping over the handler stack. Instead, defer
2819 // the numbering of the catch handlers until we are done popping.
2820 SmallVector PoppedCatches;
2821 for (int I = HandlerStack.size() - 1; I >= FirstMismatch; --I) {
2822 std::unique_ptr Handler = HandlerStack.pop_back_val();
2823 if (isa(Handler.get()))
2824 PoppedCatches.push_back(cast(Handler.release()));
2825 }
2826
2827 int TryHigh = NextState - 1;
2828 int LastTryLowIdx = 0;
2829 for (int I = 0, E = PoppedCatches.size(); I != E; ++I) {
2830 CatchHandler *CH = PoppedCatches[I];
2831 DEBUG(dbgs() << "Popped handler with state " << CH->getEHState() << "\n");
2832 if (I + 1 == E || CH->getEHState() != PoppedCatches[I + 1]->getEHState()) {
2833 int TryLow = CH->getEHState();
2834 auto Handlers =
2835 makeArrayRef(&PoppedCatches[LastTryLowIdx], I - LastTryLowIdx + 1);
2836 DEBUG(dbgs() << "createTryBlockMapEntry(" << TryLow << ", " << TryHigh);
2837 for (size_t J = 0; J < Handlers.size(); ++J) {
2838 DEBUG(dbgs() << ", ");
2839 print_name(Handlers[J]->getHandlerBlockOrFunc());
2840 }
2841 DEBUG(dbgs() << ")\n");
2842 createTryBlockMapEntry(TryLow, TryHigh, Handlers);
2843 LastTryLowIdx = I + 1;
2844 }
2845 }
2846
2847 for (CatchHandler *CH : PoppedCatches) {
2848 if (auto *F = dyn_cast(CH->getHandlerBlockOrFunc())) {
2849 if (FuncInfo.LastInvokeVisited[F]) {
2850 DEBUG(dbgs() << "Assigning base state " << NextState << " to ");
2851 print_name(F);
2852 DEBUG(dbgs() << '\n');
2853 FuncInfo.HandlerBaseState[F] = NextState;
2854 DEBUG(dbgs() << "createUnwindMapEntry(" << currentEHNumber()
2855 << ", null)\n");
2856 createUnwindMapEntry(currentEHNumber(), nullptr);
2857 ++NextState;
2858 calculateStateNumbers(*F);
2859 }
2860 else {
2861 DEBUG(dbgs() << "Deferring handling of ");
2862 print_name(F);
2863 DEBUG(dbgs() << " until last invoke visited.\n");
2864 }
2865 }
2866 delete CH;
2867 }
2868 }
2869
2870 void WinEHNumbering::calculateStateNumbers(const Function &F) {
2871 auto I = VisitedHandlers.insert(&F);
2872 if (!I.second)
2873 return; // We've already visited this handler, don't renumber it.
2874
2875 int OldBaseState = CurrentBaseState;
2876 if (FuncInfo.HandlerBaseState.count(&F)) {
2877 CurrentBaseState = FuncInfo.HandlerBaseState[&F];
2878 }
2879
2880 size_t SavedHandlerStackSize = HandlerStack.size();
2881
2882 DEBUG(dbgs() << "Calculating state numbers for: " << F.getName() << '\n');
2883 SmallVector, 4> ActionList;
2884 for (const BasicBlock &BB : F) {
2885 for (const Instruction &I : BB) {
2886 const auto *CI = dyn_cast(&I);
2887 if (!CI || CI->doesNotThrow())
2888 continue;
2889 processCallSite(None, CI);
2890 }
2891 const auto *II = dyn_cast(BB.getTerminator());
2892 if (!II)
2893 continue;
2894 const LandingPadInst *LPI = II->getLandingPadInst();
2895 auto *ActionsCall = dyn_cast(LPI->getNextNode());
2896 if (!ActionsCall)
2897 continue;
2898 parseEHActions(ActionsCall, ActionList);
2899 if (ActionList.empty())
2900 continue;
2901 processCallSite(ActionList, II);
2902 ActionList.clear();
2903 FuncInfo.EHPadStateMap[LPI] = currentEHNumber();
2904 DEBUG(dbgs() << "Assigning state " << currentEHNumber()
2905 << " to landing pad at " << LPI->getParent()->getName()
2906 << '\n');
2907 }
2908
2909 // Pop any actions that were pushed on the stack for this function.
2910 popUnmatchedActions(SavedHandlerStackSize);
2911
2912 DEBUG(dbgs() << "Assigning max state " << NextState - 1
2913 << " to " << F.getName() << '\n');
2914 FuncInfo.CatchHandlerMaxState[&F] = NextState - 1;
2915
2916 CurrentBaseState = OldBaseState;
2917 }
2918
2919 // This function follows the same basic traversal as calculateStateNumbers
2920 // but it is necessary to identify the root landing pad associated
2921 // with each action before we start assigning state numbers.
2922 void WinEHNumbering::findActionRootLPads(const Function &F) {
2923 auto I = VisitedHandlers.insert(&F);
2924 if (!I.second)
2925 return; // We've already visited this handler, don't revisit it.
2926
2927 SmallVector, 4> ActionList;
2928 for (const BasicBlock &BB : F) {
2929 const auto *II = dyn_cast(BB.getTerminator());
2930 if (!II)
2931 continue;
2932 const LandingPadInst *LPI = II->getLandingPadInst();
2933 auto *ActionsCall = dyn_cast(LPI->getNextNode());
2934 if (!ActionsCall)
2935 continue;
2936
2937 assert(ActionsCall->getIntrinsicID() == Intrinsic::eh_actions);
2938 parseEHActions(ActionsCall, ActionList);
2939 if (ActionList.empty())
2940 continue;
2941 for (int I = 0, E = ActionList.size(); I < E; ++I) {
2942 if (auto *Handler
2943 = dyn_cast(ActionList[I]->getHandlerBlockOrFunc())) {
2944 FuncInfo.LastInvoke[Handler] = II;
2945 // Don't replace the root landing pad if we previously saw this
2946 // handler in a different function.
2947 if (FuncInfo.RootLPad.count(Handler) &&
2948 FuncInfo.RootLPad[Handler]->getParent()->getParent() != &F)
2949 continue;
2950 DEBUG(dbgs() << "Setting root lpad for ");
2951 print_name(Handler);
2952 DEBUG(dbgs() << " to " << LPI->getParent()->getName() << '\n');
2953 FuncInfo.RootLPad[Handler] = LPI;
2954 }
2955 }
2956 // Walk the actions again and look for nested handlers. This has to
2957 // happen after all of the actions have been processed in the current
2958 // function.
2959 for (int I = 0, E = ActionList.size(); I < E; ++I)
2960 if (auto *Handler
2961 = dyn_cast(ActionList[I]->getHandlerBlockOrFunc()))
2962 findActionRootLPads(*Handler);
2963 ActionList.clear();
2964 }
29652612 }
29662613
29672614 static const CatchPadInst *getSingleCatchPadPredecessor(const BasicBlock *BB) {
31572804 return cast(User)->unwindsToCaller();
31582805 }
31592806
3160 void llvm::calculateSEHStateNumbers(const Function *ParentFn,
2807 void llvm::calculateSEHStateNumbers(const Function *Fn,
31612808 WinEHFuncInfo &FuncInfo) {
31622809 // Don't compute state numbers twice.
31632810 if (!FuncInfo.SEHUnwindMap.empty())
31642811 return;
31652812
3166 for (const BasicBlock &BB : *ParentFn) {
2813 for (const BasicBlock &BB : *Fn) {
31672814 if (!BB.isEHPad() || !doesEHPadUnwindToCaller(BB.getFirstNonPHI()))
31682815 continue;
31692816 calculateExplicitSEHStateNumbers(FuncInfo, BB, -1);
31702817 }
31712818 }
31722819
3173 void llvm::calculateWinCXXEHStateNumbers(const Function *ParentFn,
2820 void llvm::calculateWinCXXEHStateNumbers(const Function *Fn,
31742821 WinEHFuncInfo &FuncInfo) {
31752822 // Return if it's already been done.
31762823 if (!FuncInfo.EHPadStateMap.empty())
31772824 return;
31782825
3179 bool IsExplicit = false;
3180 for (const BasicBlock &BB : *ParentFn) {
2826 for (const BasicBlock &BB : *Fn) {
31812827 if (!BB.isEHPad())
31822828 continue;
2829 if (BB.isLandingPad())
2830 report_fatal_error("MSVC C++ EH cannot use landingpads");
31832831 const Instruction *FirstNonPHI = BB.getFirstNonPHI();
31842832 // Skip cleanupendpads; they are exits, not entries.
31852833 if (isa(FirstNonPHI))
31872835 if (!doesEHPadUnwindToCaller(FirstNonPHI))
31882836 continue;
31892837 calculateExplicitCXXStateNumbers(FuncInfo, BB, -1);
3190 IsExplicit = true;
3191 }
3192
3193 if (IsExplicit)
3194 return;
3195
3196 WinEHNumbering Num(FuncInfo);
3197 Num.findActionRootLPads(*ParentFn);
3198 // The VisitedHandlers list is used by both findActionRootLPads and
3199 // calculateStateNumbers, but both functions need to visit all handlers.
3200 Num.VisitedHandlers.clear();
3201 Num.calculateStateNumbers(*ParentFn);
3202 // Pop everything on the handler stack.
3203 // It may be necessary to call this more than once because a handler can
3204 // be pushed on the stack as a result of clearing the stack.
3205 while (!Num.HandlerStack.empty())
3206 Num.processCallSite(None, ImmutableCallSite());
2838 }
32072839 }
32082840
32092841 void WinEHPrepare::replaceTerminatePadWithCleanup(Function &F) {
26552655 const Function *WinEHParent = nullptr;
26562656 if (MMI.hasWinEHFuncInfo(Fn))
26572657 WinEHParent = MMI.getWinEHParent(Fn);
2658 bool IsWinEHOutlined = WinEHParent && WinEHParent != Fn;
26592658 bool IsWinEHParent = WinEHParent && WinEHParent == Fn;
26602659
26612660 // Figure out if XMM registers are in use.
27472746
27482747 if (!MemOps.empty())
27492748 Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOps);
2750 } else if (IsWin64 && IsWinEHOutlined) {
2751 // Get to the caller-allocated home save location. Add 8 to account
2752 // for the return address.
2753 int HomeOffset = TFI.getOffsetOfLocalArea() + 8;
2754 FuncInfo->setRegSaveFrameIndex(MFI->CreateFixedObject(
2755 /*Size=*/1, /*SPOffset=*/HomeOffset + 8, /*Immutable=*/false));
2756
2757 MMI.getWinEHFuncInfo(Fn)
2758 .CatchHandlerParentFrameObjIdx[const_cast(Fn)] =
2759 FuncInfo->getRegSaveFrameIndex();
2760
2761 // Store the second integer parameter (rdx) into rsp+16 relative to the
2762 // stack pointer at the entry of the function.
2763 SDValue RSFIN = DAG.getFrameIndex(FuncInfo->getRegSaveFrameIndex(),
2764 getPointerTy(DAG.getDataLayout()));
2765 unsigned GPR = MF.addLiveIn(X86::RDX, &X86::GR64RegClass);
2766 SDValue Val = DAG.getCopyFromReg(Chain, dl, GPR, MVT::i64);
2767 Chain = DAG.getStore(
2768 Val.getValue(1), dl, Val, RSFIN,
2769 MachinePointerInfo::getFixedStack(DAG.getMachineFunction(),
2770 FuncInfo->getRegSaveFrameIndex()),
2771 /*isVolatile=*/true, /*isNonTemporal=*/false, /*Alignment=*/0);
27722749 }
27732750
27742751 if (isVarArg && MFI->hasMustTailInVarArgFunc()) {
436436 // Set up RegNodeEscapeIndex
437437 int RegNodeEscapeIndex = escapeRegNode(F);
438438 FuncInfo.EHRegNodeEscapeIndex = RegNodeEscapeIndex;
439
440 // Only insert stores in catch handlers.
441 Constant *FI8 =
442 ConstantExpr::getBitCast(&F, Type::getInt8PtrTy(TheModule->getContext()));
443 for (auto P : FuncInfo.HandlerBaseState) {
444 Function *Handler = const_cast(P.first);
445 int BaseState = P.second;
446 IRBuilder<> Builder(&Handler->getEntryBlock(),
447 Handler->getEntryBlock().begin());
448 // FIXME: Find and reuse such a call if present.
449 Value *ParentFP = Builder.CreateCall(FrameAddress, {Builder.getInt32(1)});
450 Value *RecoveredRegNode = Builder.CreateCall(
451 FrameRecover, {FI8, ParentFP, Builder.getInt32(RegNodeEscapeIndex)});
452 RecoveredRegNode =
453 Builder.CreateBitCast(RecoveredRegNode, RegNodeTy->getPointerTo(0));
454 addStateStoresToFunclet(RecoveredRegNode, FuncInfo, *Handler, BaseState);
455 }
456439 }
457440
458441 /// Escape RegNode so that we can access it from child handlers. Find the call
+0
-47
test/CodeGen/WinEH/cppeh-prepared-catch-all.ll less more
None ; RUN: llc < %s | FileCheck %s
1
2 target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
3 target triple = "x86_64-pc-windows-msvc"
4
5 ; This test case is equivalent to:
6 ; extern "C" void may_throw();
7 ; extern "C" void test_catch_all() {
8 ; try {
9 ; may_throw();
10 ; } catch (...) {
11 ; }
12 ; }
13
14 declare void @may_throw() #1
15 declare i32 @__CxxFrameHandler3(...)
16 declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #2
17 declare void @llvm.eh.endcatch() #2
18
19 ; Function Attrs: nounwind uwtable
20 define void @test_catch_all() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
21 entry:
22 invoke void @may_throw()
23 to label %try.cont unwind label %lpad
24
25 lpad: ; preds = %entry
26 %0 = landingpad { i8*, i32 }
27 catch i8* null
28 %1 = extractvalue { i8*, i32 } %0, 0
29 tail call void @llvm.eh.begincatch(i8* %1, i8* null) #2
30 tail call void @llvm.eh.endcatch() #2
31 br label %try.cont
32
33 try.cont: ; preds = %entry, %lpad
34 ret void
35 }
36
37 ; CHECK-LABEL: $handlerMap$0$test_catch_all:
38 ; CHECK: .long {{[0-9]+}}
39 ; CHECK: .long 0
40 ; CHECK: .long 0
41 ; CHECK: .long test_catch_all.catch@IMGREL
42 ; CHECK: .long .Ltest_catch_all.catch$parent_frame_offset
43
44 attributes #0 = { nounwind uwtable "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-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" }
45 attributes #1 = { "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-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" }
46 attributes #2 = { nounwind }
+0
-165
test/CodeGen/WinEH/cppeh-prepared-catch-reordered.ll less more
None ; RUN: llc < %s | FileCheck %s
1
2 ; Verify that we get the right frame escape label when the catch comes after the
3 ; parent function.
4
5 ; This test case is equivalent to:
6 ; int main() {
7 ; try {
8 ; throw 42;
9 ; } catch (int e) {
10 ; printf("e: %d\n", e);
11 ; }
12 ; }
13
14 target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
15 target triple = "x86_64-pc-windows-msvc"
16
17 %rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
18 %eh.CatchableType = type { i32, i32, i32, i32, i32, i32, i32 }
19 %eh.CatchableTypeArray.1 = type { i32, [1 x i32] }
20 %eh.ThrowInfo = type { i32, i32, i32, i32 }
21 %eh.CatchHandlerType = type { i32, i8* }
22
23 $"\01??_R0H@8" = comdat any
24
25 $"_CT??_R0H@84" = comdat any
26
27 $_CTA1H = comdat any
28
29 $_TI1H = comdat any
30
31 $"\01??_C@_06PNOAJMHG@e?3?5?$CFd?6?$AA@" = comdat any
32
33 @"\01??_7type_info@@6B@" = external constant i8*
34 @"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
35 @__ImageBase = external constant i8
36 @"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 4, i32 0 }, section ".xdata", comdat
37 @_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0H@84" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat
38 @_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableTypeArray.1* @_CTA1H to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section ".xdata", comdat
39 @llvm.eh.handlertype.H.0 = private unnamed_addr constant %eh.CatchHandlerType { i32 0, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) }, section "llvm.metadata"
40 @"\01??_C@_06PNOAJMHG@e?3?5?$CFd?6?$AA@" = linkonce_odr unnamed_addr constant [7 x i8] c"e: %d\0A\00", comdat, align 1
41
42 declare void @_CxxThrowException(i8*, %eh.ThrowInfo*)
43
44 ; Function Attrs: uwtable
45 define i32 @main() #1 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
46 entry:
47 %tmp.i = alloca i32, align 4
48 %e = alloca i32, align 4
49 %0 = bitcast i32* %tmp.i to i8*
50 store i32 42, i32* %tmp.i, align 4, !tbaa !2
51 call void (...) @llvm.localescape(i32* %e)
52 invoke void @_CxxThrowException(i8* %0, %eh.ThrowInfo* @_TI1H) #6
53 to label %.noexc unwind label %lpad1
54
55 .noexc: ; preds = %entry
56 unreachable
57
58 lpad1: ; preds = %entry
59 %1 = landingpad { i8*, i32 }
60 catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.0
61 %recover = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*), i32 0, i8* (i8*, i8*)* @main.catch)
62 indirectbr i8* %recover, [label %try.cont.split]
63
64 try.cont.split: ; preds = %lpad1
65 ret i32 0
66 }
67
68 ; CHECK-LABEL: main:
69 ; CHECK: .seh_handlerdata
70 ; CHECK: .long ($cppxdata$main)@IMGREL
71
72 declare i32 @__CxxFrameHandler3(...)
73
74 ; Function Attrs: nounwind readnone
75 declare i32 @llvm.eh.typeid.for(i8*) #2
76
77 ; Function Attrs: nounwind
78 declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #3
79
80 ; Function Attrs: nounwind
81 declare i32 @printf(i8* nocapture readonly, ...) #4
82
83 ; Function Attrs: nounwind
84 declare void @llvm.eh.endcatch() #3
85
86 ; Function Attrs: nounwind
87 declare void @llvm.lifetime.start(i64, i8* nocapture) #3
88
89 ; Function Attrs: nounwind
90 declare i8* @llvm.eh.actions(...) #3
91
92 define internal i8* @main.catch(i8*, i8*) #5 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
93 entry:
94 %e.i8 = call i8* @llvm.localrecover(i8* bitcast (i32 ()* @main to i8*), i8* %1, i32 0)
95 %e = bitcast i8* %e.i8 to i32*
96 %2 = bitcast i32* %e to i8*
97 %3 = load i32, i32* %e, align 4, !tbaa !2
98 %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @"\01??_C@_06PNOAJMHG@e?3?5?$CFd?6?$AA@", i64 0, i64 0), i32 %3)
99 invoke void @llvm.donothing()
100 to label %entry.split unwind label %stub
101
102 entry.split: ; preds = %entry
103 ret i8* blockaddress(@main, %try.cont.split)
104
105 stub: ; preds = %entry
106 %4 = landingpad { i8*, i32 }
107 cleanup
108 %recover = call i8* (...) @llvm.eh.actions()
109 unreachable
110 }
111
112 ; CHECK-LABEL: main.catch:
113 ; CHECK: .seh_handlerdata
114 ; CHECK: .long ($cppxdata$main)@IMGREL
115
116 ; CHECK: .align 4
117 ; CHECK-NEXT: $cppxdata$main:
118 ; CHECK-NEXT: .long 429065506
119 ; CHECK-NEXT: .long 2
120 ; CHECK-NEXT: .long ($stateUnwindMap$main)@IMGREL
121 ; CHECK-NEXT: .long 1
122 ; CHECK-NEXT: .long ($tryMap$main)@IMGREL
123 ; CHECK-NEXT: .long 3
124 ; CHECK-NEXT: .long ($ip2state$main)@IMGREL
125 ; CHECK-NEXT: .long 40
126 ; CHECK-NEXT: .long 0
127 ; CHECK-NEXT: .long 1
128
129 ; Make sure we get the right frame escape label.
130
131 ; CHECK: $handlerMap$0$main:
132 ; CHECK-NEXT: .long 0
133 ; CHECK-NEXT: .long "??_R0H@8"@IMGREL
134 ; CHECK-NEXT: .long .Lmain$frame_escape_0
135 ; CHECK-NEXT: .long main.catch@IMGREL
136 ; CHECK-NEXT: .long .Lmain.catch$parent_frame_offset
137
138 ; Function Attrs: nounwind readnone
139 declare void @llvm.donothing() #2
140
141 ; Function Attrs: nounwind
142 declare void @llvm.localescape(...) #3
143
144 ; Function Attrs: nounwind readnone
145 declare i8* @llvm.localrecover(i8*, i8*, i32) #2
146
147 attributes #0 = { noreturn uwtable "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-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" }
148 attributes #1 = { uwtable "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-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" "wineh-parent"="main" }
149 attributes #2 = { nounwind readnone }
150 attributes #3 = { nounwind }
151 attributes #4 = { nounwind "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-cpu"="x86-64" "unsafe-fp-math"="false" "use-soft-float"="false" }
152 attributes #5 = { "wineh-parent"="main" }
153 attributes #6 = { noreturn }
154
155 !llvm.module.flags = !{!0}
156 !llvm.ident = !{!1}
157
158 !0 = !{i32 1, !"PIC Level", i32 2}
159 !1 = !{!"clang version 3.7.0 "}
160 !2 = !{!3, !3, i64 0}
161 !3 = !{!"int", !4, i64 0}
162 !4 = !{!"omnipotent char", !5, i64 0}
163 !5 = !{!"Simple C/C++ TBAA"}
164
+0
-232
test/CodeGen/WinEH/cppeh-prepared-catch.ll less more
None ; RUN: llc -mtriple=x86_64-windows-msvc < %s | FileCheck %s --check-prefix=CHECK --check-prefix=X64
1 ; RUN: llc -mtriple=i686-windows-msvc < %s | FileCheck %s --check-prefix=CHECK --check-prefix=X86
2
3 ; This test case is equivalent to:
4 ; void f() {
5 ; try {
6 ; try {
7 ; may_throw();
8 ; } catch (int &) {
9 ; may_throw();
10 ; }
11 ; may_throw();
12 ; } catch (double) {
13 ; }
14 ; }
15
16
17 %rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
18 %eh.CatchHandlerType = type { i32, i8* }
19
20 $"\01??_R0N@8" = comdat any
21
22 $"\01??_R0H@8" = comdat any
23
24 @"\01??_7type_info@@6B@" = external constant i8*
25 @"\01??_R0N@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".N\00" }, comdat
26 @llvm.eh.handlertype.N.0 = private unnamed_addr constant %eh.CatchHandlerType { i32 0, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0N@8" to i8*) }, section "llvm.metadata"
27 @"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
28 @llvm.eh.handlertype.H.8 = private unnamed_addr constant %eh.CatchHandlerType { i32 8, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) }, section "llvm.metadata"
29
30 define internal i8* @"\01?f@@YAXXZ.catch"(i8*, i8*) #4 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
31 entry:
32 %.i8 = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?f@@YAXXZ" to i8*), i8* %1, i32 0)
33 %bc2 = bitcast i8* %.i8 to i32**
34 %bc3 = bitcast i32** %bc2 to i8*
35 invoke void @"\01?may_throw@@YAXXZ"()
36 to label %invoke.cont2 unwind label %lpad1
37
38 invoke.cont2: ; preds = %entry
39 ret i8* blockaddress(@"\01?f@@YAXXZ", %try.cont)
40
41 lpad1: ; preds = %entry
42 %lp4 = landingpad { i8*, i32 }
43 cleanup
44 catch %eh.CatchHandlerType* @llvm.eh.handlertype.N.0
45 %recover = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.N.0 to i8*), i32 1, i8* (i8*, i8*)* @"\01?f@@YAXXZ.catch1")
46 indirectbr i8* %recover, [label %invoke.cont2]
47 }
48
49 ; CHECK-LABEL: "?f@@YAXXZ.catch":
50 ; No code should be generated for the indirectbr.
51 ; CHECK-NOT: jmp{{[ql]}} *
52 ; X64: .seh_handlerdata
53 ; X64-NEXT: .long ("$cppxdata$?f@@YAXXZ")@IMGREL
54
55
56 define internal i8* @"\01?f@@YAXXZ.catch1"(i8*, i8*) #4 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
57 entry:
58 %.i8 = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?f@@YAXXZ" to i8*), i8* %1, i32 1)
59 %2 = bitcast i8* %.i8 to double*
60 %3 = bitcast double* %2 to i8*
61 invoke void () @llvm.donothing()
62 to label %done unwind label %lpad
63
64 done:
65 ret i8* blockaddress(@"\01?f@@YAXXZ", %try.cont8)
66
67 lpad: ; preds = %entry
68 %4 = landingpad { i8*, i32 }
69 cleanup
70 %recover = call i8* (...) @llvm.eh.actions()
71 unreachable
72 }
73
74 ; CHECK-LABEL: "?f@@YAXXZ.catch1":
75 ; No code should be generated for the indirectbr.
76 ; CHECK-NOT: jmp{{[ql]}} *
77 ; X64: ".L?f@@YAXXZ.catch1$parent_frame_offset" = 16
78 ; X64: movq %rdx, 16(%rsp)
79 ; X64: .seh_handlerdata
80 ; X64: .long ("$cppxdata$?f@@YAXXZ")@IMGREL
81
82 define void @"\01?f@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
83 entry:
84 %exn.slot = alloca i8*
85 %ehselector.slot = alloca i32
86 %0 = alloca i32*, align 8
87 %1 = alloca double, align 8
88 call void (...) @llvm.localescape(i32** %0, double* %1)
89 invoke void @"\01?may_throw@@YAXXZ"()
90 to label %invoke.cont unwind label %lpad2
91
92 invoke.cont: ; preds = %entry
93 br label %try.cont
94
95 lpad2: ; preds = %entry
96 %2 = landingpad { i8*, i32 }
97 catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.8
98 catch %eh.CatchHandlerType* @llvm.eh.handlertype.N.0
99 %recover = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.8 to i8*), i32 0, i8* (i8*, i8*)* @"\01?f@@YAXXZ.catch", i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.N.0 to i8*), i32 1, i8* (i8*, i8*)* @"\01?f@@YAXXZ.catch1")
100 indirectbr i8* %recover, [label %try.cont, label %try.cont8]
101
102 try.cont: ; preds = %lpad2, %invoke.cont
103 invoke void @"\01?may_throw@@YAXXZ"()
104 to label %try.cont8 unwind label %lpad1
105
106 lpad1:
107 %3 = landingpad { i8*, i32 }
108 catch %eh.CatchHandlerType* @llvm.eh.handlertype.N.0
109 %recover2 = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.N.0 to i8*), i32 1, i8* (i8*, i8*)* @"\01?f@@YAXXZ.catch1")
110 indirectbr i8* %recover2, [label %try.cont8]
111
112 try.cont8: ; preds = %lpad2, %try.cont
113 ret void
114 }
115
116 ; CHECK-LABEL: "?f@@YAXXZ":
117 ; No code should be generated for the indirectbr.
118 ; CHECK-NOT: jmp{{[ql]}} *
119
120 ; X64: .seh_handlerdata
121 ; X64-NEXT: .long ("$cppxdata$?f@@YAXXZ")@IMGREL
122 ; X86: .section .xdata,"dr"
123
124 ; CHECK: .align 4
125
126 ; X64: "$cppxdata$?f@@YAXXZ":
127 ; X64-NEXT: .long 429065506
128 ; X64-NEXT: .long 4
129 ; X64-NEXT: .long ("$stateUnwindMap$?f@@YAXXZ")@IMGREL
130 ; X64-NEXT: .long 2
131 ; X64-NEXT: .long ("$tryMap$?f@@YAXXZ")@IMGREL
132 ; X64-NEXT: .long 6
133 ; X64-NEXT: .long ("$ip2state$?f@@YAXXZ")@IMGREL
134 ; X64-NEXT: .long 32
135 ; X64-NEXT: .long 0
136 ; X64-NEXT: .long 1
137
138 ; X86: "L__ehtable$?f@@YAXXZ":
139 ; X86-NEXT: .long 429065506
140 ; X86-NEXT: .long 4
141 ; X86-NEXT: .long ("$stateUnwindMap$?f@@YAXXZ")
142 ; X86-NEXT: .long 2
143 ; X86-NEXT: .long ("$tryMap$?f@@YAXXZ")
144 ; X86-NEXT: .long 0
145 ; X86-NEXT: .long 0
146 ; X86-NEXT: .long 0
147 ; X86-NEXT: .long 1
148
149
150 ; CHECK-NEXT:"$stateUnwindMap$?f@@YAXXZ":
151 ; CHECK-NEXT: .long -1
152 ; CHECK-NEXT: .long 0
153 ; CHECK-NEXT: .long 0
154 ; CHECK-NEXT: .long 0
155 ; CHECK-NEXT: .long 0
156 ; CHECK-NEXT: .long 0
157 ; CHECK-NEXT: .long -1
158 ; CHECK-NEXT: .long 0
159 ; CHECK-NEXT:"$tryMap$?f@@YAXXZ":
160 ; CHECK-NEXT: .long 1
161 ; CHECK-NEXT: .long 1
162 ; CHECK-NEXT: .long 2
163 ; CHECK-NEXT: .long 1
164 ; CHECK-NEXT: .long ("$handlerMap$0$?f@@YAXXZ")
165 ; CHECK-NEXT: .long 0
166 ; CHECK-NEXT: .long 2
167 ; CHECK-NEXT: .long 3
168 ; CHECK-NEXT: .long 1
169 ; CHECK-NEXT: .long ("$handlerMap$1$?f@@YAXXZ")
170 ; CHECK-NEXT:"$handlerMap$0$?f@@YAXXZ":
171 ; CHECK-NEXT: .long 8
172 ; CHECK-NEXT: .long "??_R0H@8"
173 ; CHECK-NEXT: .long "{{.?}}L?f@@YAXXZ$frame_escape_0"
174 ; CHECK-NEXT: .long "?f@@YAXXZ.catch"
175 ; X64-NEXT: .long ".L?f@@YAXXZ.catch$parent_frame_offset"
176 ; CHECK-NEXT:"$handlerMap$1$?f@@YAXXZ":
177 ; CHECK-NEXT: .long 0
178 ; CHECK-NEXT: .long "??_R0N@8"
179 ; CHECK-NEXT: .long "{{.?}}L?f@@YAXXZ$frame_escape_1"
180 ; CHECK-NEXT: .long "?f@@YAXXZ.catch1"
181 ; X64-NEXT: .long ".L?f@@YAXXZ.catch1$parent_frame_offset"
182
183 ; X64-NEXT:"$ip2state$?f@@YAXXZ":
184 ; X64-NEXT: .long .Lfunc_begin0
185 ; X64-NEXT: .long 2
186 ; X64-NEXT: .long .Ltmp0
187 ; X64-NEXT: .long 0
188 ; X64-NEXT: .long .Lfunc_begin1
189 ; X64-NEXT: .long 3
190 ; X64-NEXT: .long .Lfunc_begin2
191 ; X64-NEXT: .long -1
192 ; X64-NEXT: .long .Ltmp13
193 ; X64-NEXT: .long 1
194 ; X64-NEXT: .long .Ltmp16
195 ; X64-NEXT: .long 0
196
197
198 ; X86: "___ehhandler$?f@@YAXXZ": # @"__ehhandler$?f@@YAXXZ"
199 ; X86: movl $"L__ehtable$?f@@YAXXZ", %eax
200 ; X86: jmp ___CxxFrameHandler3 # TAILCALL
201
202
203 declare void @"\01?may_throw@@YAXXZ"() #1
204
205 declare i32 @__CxxFrameHandler3(...)
206
207 ; Function Attrs: nounwind readnone
208 declare i32 @llvm.eh.typeid.for(i8*) #2
209
210 ; Function Attrs: nounwind
211 declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #3
212
213 ; Function Attrs: nounwind
214 declare void @llvm.eh.endcatch() #3
215
216 ; Function Attrs: nounwind
217 declare i8* @llvm.eh.actions(...) #3
218
219 ; Function Attrs: nounwind
220 declare void @llvm.localescape(...) #3
221
222 ; Function Attrs: nounwind readnone
223 declare i8* @llvm.localrecover(i8*, i8*, i32) #2
224
225 declare void @llvm.donothing()
226
227 attributes #0 = { "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" "wineh-parent"="?f@@YAXXZ" }
228 attributes #1 = { "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" }
229 attributes #2 = { nounwind readnone }
230 attributes #3 = { nounwind }
231 attributes #4 = { "wineh-parent"="?f@@YAXXZ" }
+0
-245
test/CodeGen/WinEH/cppeh-prepared-cleanups.ll less more
None ; RUN: llc < %s | FileCheck %s
1
2 target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
3 target triple = "x86_64-pc-windows-msvc"
4
5 %rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
6 %eh.CatchableType = type { i32, i32, i32, i32, i32, i32, i32 }
7 %eh.CatchableTypeArray.1 = type { i32, [1 x i32] }
8 %eh.ThrowInfo = type { i32, i32, i32, i32 }
9 %struct.S = type { i8 }
10
11 $"\01??_DS@@QEAA@XZ" = comdat any
12
13 $"\01??_R0H@8" = comdat any
14
15 $"_CT??_R0H@84" = comdat any
16
17 $_CTA1H = comdat any
18
19 $_TI1H = comdat any
20
21 @"\01??_7type_info@@6B@" = external constant i8*
22 @"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
23 @__ImageBase = external constant i8
24 @"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 4, i32 0 }, section ".xdata", comdat
25 @_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0H@84" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat
26 @_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableTypeArray.1* @_CTA1H to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section ".xdata", comdat
27
28
29 ; CHECK-LABEL: "?test1@@YAXXZ":
30 ; CHECK: .seh_handlerdata
31 ; CHECK-NEXT: .long ("$cppxdata$?test1@@YAXXZ")@IMGREL
32 ; CHECK-NEXT: .align 4
33 ; CHECK-NEXT:"$cppxdata$?test1@@YAXXZ":
34 ; CHECK-NEXT: .long 429065506
35 ; CHECK-NEXT: .long 1
36 ; CHECK-NEXT: .long ("$stateUnwindMap$?test1@@YAXXZ")@IMGREL
37 ; CHECK-NEXT: .long 0
38 ; CHECK-NEXT: .long 0
39 ; CHECK-NEXT: .long 2
40 ; CHECK-NEXT: .long ("$ip2state$?test1@@YAXXZ")@IMGREL
41 ; CHECK-NEXT: .long 32
42 ; CHECK-NEXT: .long 0
43 ; CHECK-NEXT: .long 1
44 ; CHECK-NEXT:"$stateUnwindMap$?test1@@YAXXZ":
45 ; CHECK-NEXT: .long -1
46 ; CHECK-NEXT: .long "?test1@@YAXXZ.cleanup"@IMGREL
47 ; CHECK-NEXT:"$ip2state$?test1@@YAXXZ":
48 ; CHECK-NEXT: .long .Lfunc_begin0@IMGREL
49 ; CHECK-NEXT: .long -1
50 ; CHECK-NEXT: .long .Ltmp0@IMGREL
51 ; CHECK-NEXT: .long 0
52
53 define void @"\01?test1@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
54 entry:
55 %unwindhelp = alloca i64
56 %tmp = alloca i32, align 4
57 %exn.slot = alloca i8*
58 %ehselector.slot = alloca i32
59 store i32 0, i32* %tmp
60 %0 = bitcast i32* %tmp to i8*
61 call void (...) @llvm.localescape()
62 store volatile i64 -2, i64* %unwindhelp
63 %1 = bitcast i64* %unwindhelp to i8*
64 call void @llvm.eh.unwindhelp(i8* %1)
65 invoke void @_CxxThrowException(i8* %0, %eh.ThrowInfo* @_TI1H) #8
66 to label %unreachable unwind label %lpad1
67
68 lpad1: ; preds = %entry
69 %2 = landingpad { i8*, i32 }
70 cleanup
71 %recover = call i8* (...) @llvm.eh.actions(i32 0, void (i8*, i8*)* @"\01?test1@@YAXXZ.cleanup")
72 indirectbr i8* %recover, []
73
74 unreachable: ; preds = %entry
75 unreachable
76 }
77
78 declare void @_CxxThrowException(i8*, %eh.ThrowInfo*)
79
80 declare i32 @__CxxFrameHandler3(...)
81
82 ; Function Attrs: nounwind
83 define linkonce_odr void @"\01??_DS@@QEAA@XZ"(%struct.S* %this) unnamed_addr #1 comdat align 2 {
84 entry:
85 %this.addr = alloca %struct.S*, align 8
86 store %struct.S* %this, %struct.S** %this.addr, align 8
87 %this1 = load %struct.S*, %struct.S** %this.addr
88 call void @"\01??1S@@QEAA@XZ"(%struct.S* %this1) #4
89 ret void
90 }
91
92 ; CHECK-LABEL: "?test2@@YAX_N@Z":
93 ; CHECK: .seh_handlerdata
94 ; CHECK-NEXT: .long ("$cppxdata$?test2@@YAX_N@Z")@IMGREL
95 ; CHECK-NEXT: .align 4
96 ; CHECK-NEXT:"$cppxdata$?test2@@YAX_N@Z":
97 ; CHECK-NEXT: .long 429065506
98 ; CHECK-NEXT: .long 2
99 ; CHECK-NEXT: .long ("$stateUnwindMap$?test2@@YAX_N@Z")@IMGREL
100 ; CHECK-NEXT: .long 0
101 ; CHECK-NEXT: .long 0
102 ; CHECK-NEXT: .long 4
103 ; CHECK-NEXT: .long ("$ip2state$?test2@@YAX_N@Z")@IMGREL
104 ; CHECK-NEXT: .long 40
105 ; CHECK-NEXT: .long 0
106 ; CHECK-NEXT: .long 1
107 ; CHECK-NEXT:"$stateUnwindMap$?test2@@YAX_N@Z":
108 ; CHECK-NEXT: .long -1
109 ; CHECK-NEXT: .long "?test2@@YAX_N@Z.cleanup"@IMGREL
110 ; CHECK-NEXT: .long 0
111 ; CHECK-NEXT: .long "?test2@@YAX_N@Z.cleanup1"@IMGREL
112 ; CHECK-NEXT:"$ip2state$?test2@@YAX_N@Z":
113 ; CHECK-NEXT: .long .Lfunc_begin1@IMGREL
114 ; CHECK-NEXT: .long -1
115 ; CHECK-NEXT: .long .Ltmp7@IMGREL
116 ; CHECK-NEXT: .long 0
117 ; CHECK-NEXT: .long .Ltmp9@IMGREL
118 ; CHECK-NEXT: .long 1
119 ; CHECK-NEXT: .long .Ltmp12@IMGREL
120 ; CHECK-NEXT: .long 0
121
122 define void @"\01?test2@@YAX_N@Z"(i1 zeroext %b) #2 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
123 %b.addr = alloca i8, align 1
124 %s = alloca %struct.S, align 1
125 %exn.slot = alloca i8*
126 %ehselector.slot = alloca i32
127 %s1 = alloca %struct.S, align 1
128 %frombool = zext i1 %b to i8
129 store i8 %frombool, i8* %b.addr, align 1
130 call void (...) @llvm.localescape(%struct.S* %s, %struct.S* %s1)
131 call void @"\01?may_throw@@YAXXZ"()
132 invoke void @"\01?may_throw@@YAXXZ"()
133 to label %invoke.cont unwind label %lpad1
134
135 invoke.cont: ; preds = %entry
136 %1 = load i8, i8* %b.addr, align 1
137 %tobool = trunc i8 %1 to i1
138 br i1 %tobool, label %if.then, label %if.else
139
140 if.then: ; preds = %invoke.cont
141 invoke void @"\01?may_throw@@YAXXZ"()
142 to label %invoke.cont3 unwind label %lpad3
143
144 invoke.cont3: ; preds = %if.then
145 call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s1) #4
146 br label %if.end
147
148 lpad1: ; preds = %entry, %if.end
149 %2 = landingpad { i8*, i32 }
150 cleanup
151 %recover = call i8* (...) @llvm.eh.actions(i32 0, void (i8*, i8*)* @"\01?test2@@YAX_N@Z.cleanup")
152 indirectbr i8* %recover, []
153
154 lpad3: ; preds = %if.then
155 %3 = landingpad { i8*, i32 }
156 cleanup
157 %recover4 = call i8* (...) @llvm.eh.actions(i32 0, void (i8*, i8*)* @"\01?test2@@YAX_N@Z.cleanup1", i32 0, void (i8*, i8*)* @"\01?test2@@YAX_N@Z.cleanup")
158 indirectbr i8* %recover4, []
159
160 if.else: ; preds = %invoke.cont
161 call void @"\01?dont_throw@@YAXXZ"() #4
162 br label %if.end
163
164 if.end: ; preds = %if.else, %invoke.cont3
165 invoke void @"\01?may_throw@@YAXXZ"()
166 to label %invoke.cont4 unwind label %lpad1
167
168 invoke.cont4: ; preds = %if.end
169 call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s) #4
170 ret void
171 }
172
173 declare void @"\01?may_throw@@YAXXZ"() #3
174
175 ; Function Attrs: nounwind
176 declare void @"\01?dont_throw@@YAXXZ"() #1
177
178 ; Function Attrs: nounwind
179 declare void @"\01??1S@@QEAA@XZ"(%struct.S*) #1
180
181 ; Function Attrs: nounwind
182 declare i8* @llvm.eh.actions(...) #4
183
184 define internal void @"\01?test1@@YAXXZ.cleanup"(i8*, i8*) #5 {
185 entry:
186 %s = alloca %struct.S, align 1
187 call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s) #4
188 ret void
189 }
190
191 ; Function Attrs: nounwind
192 declare void @llvm.localescape(...) #4
193
194 ; Function Attrs: nounwind readnone
195 declare i8* @llvm.localrecover(i8*, i8*, i32) #6
196
197 ; Function Attrs: nounwind
198 declare void @llvm.eh.unwindhelp(i8*) #4
199
200 define internal void @"\01?test2@@YAX_N@Z.cleanup"(i8*, i8*) #7 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
201 entry:
202 %s.i8 = call i8* @llvm.localrecover(i8* bitcast (void (i1)* @"\01?test2@@YAX_N@Z" to i8*), i8* %1, i32 0)
203 %s = bitcast i8* %s.i8 to %struct.S*
204 call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s) #4
205 invoke void @llvm.donothing()
206 to label %entry.split unwind label %stub
207
208 entry.split: ; preds = %entry
209 ret void
210
211 stub: ; preds = %entry
212 %2 = landingpad { i8*, i32 }
213 cleanup
214 unreachable
215 }
216
217 define internal void @"\01?test2@@YAX_N@Z.cleanup1"(i8*, i8*) #7 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
218 entry:
219 %s1.i8 = call i8* @llvm.localrecover(i8* bitcast (void (i1)* @"\01?test2@@YAX_N@Z" to i8*), i8* %1, i32 1)
220 %s1 = bitcast i8* %s1.i8 to %struct.S*
221 call void @"\01??_DS@@QEAA@XZ"(%struct.S* %s1) #4
222 invoke void @llvm.donothing()
223 to label %entry.split unwind label %stub
224
225 entry.split: ; preds = %entry
226 ret void
227
228 stub: ; preds = %entry
229 %2 = landingpad { i8*, i32 }
230 cleanup
231 unreachable
232 }
233
234 declare void @llvm.donothing()
235
236 attributes #0 = { "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" "wineh-parent"="?test1@@YAXXZ" }
237 attributes #1 = { nounwind "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" }
238 attributes #2 = { "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" "wineh-parent"="?test2@@YAX_N@Z" }
239 attributes #3 = { "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" }
240 attributes #4 = { nounwind }
241 attributes #5 = { "wineh-parent"="?test1@@YAXXZ" }
242 attributes #6 = { nounwind readnone }
243 attributes #7 = { "wineh-parent"="?test2@@YAX_N@Z" }
244 attributes #8 = { noreturn }
+0
-289
test/CodeGen/WinEH/cppeh-state-calc-1.ll less more
None ; RUN: llc < %s | FileCheck %s
1
2 ; This test was generated from the following code.
3 ;
4 ; void test() {
5 ; try {
6 ; try {
7 ; try {
8 ; two();
9 ; throw 2;
10 ; } catch (int x) {
11 ; catch_two();
12 ; }
13 ; a();
14 ; throw 'a';
15 ; } catch (char c) {
16 ; catch_a();
17 ; }
18 ; one();
19 ; throw 1;
20 ; } catch(int x) {
21 ; catch_one();
22 ; } catch(...) {
23 ; catch_all();
24 ; }
25 ; }
26 ;
27 ; The function calls before the throws were declared as 'noexcept' and are
28 ; just here to make blocks easier to identify in the IR.
29
30 ; ModuleID = ''
31 target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
32 target triple = "x86_64-pc-windows-msvc"
33
34 %rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
35 %eh.CatchHandlerType = type { i32, i8* }
36 %eh.CatchableType = type { i32, i32, i32, i32, i32, i32, i32 }
37 %eh.CatchableTypeArray.1 = type { i32, [1 x i32] }
38 %eh.ThrowInfo = type { i32, i32, i32, i32 }
39
40 $"\01??_R0H@8" = comdat any
41
42 $"\01??_R0D@8" = comdat any
43
44 $"_CT??_R0H@84" = comdat any
45
46 $_CTA1H = comdat any
47
48 $_TI1H = comdat any
49
50 $"_CT??_R0D@81" = comdat any
51
52 $_CTA1D = comdat any
53
54 $_TI1D = comdat any
55
56 @"\01??_7type_info@@6B@" = external constant i8*
57 @"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
58 @llvm.eh.handlertype.H.0 = private unnamed_addr constant %eh.CatchHandlerType { i32 0, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) }, section "llvm.metadata"
59 @"\01??_R0D@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".D\00" }, comdat
60 @llvm.eh.handlertype.D.0 = private unnamed_addr constant %eh.CatchHandlerType { i32 0, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0D@8" to i8*) }, section "llvm.metadata"
61 @__ImageBase = external constant i8
62 @"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 4, i32 0 }, section ".xdata", comdat
63 @_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0H@84" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat
64 @_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableTypeArray.1* @_CTA1H to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section ".xdata", comdat
65 @"_CT??_R0D@81" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"\01??_R0D@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 1, i32 0 }, section ".xdata", comdat
66 @_CTA1D = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0D@81" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat
67 @_TI1D = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableTypeArray.1* @_CTA1D to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section ".xdata", comdat
68
69 ; Function Attrs: nounwind uwtable
70 define void @"\01?test@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
71 entry:
72 %tmp = alloca i32, align 4
73 %x = alloca i32, align 4
74 %tmp2 = alloca i8, align 1
75 %c = alloca i8, align 1
76 %tmp11 = alloca i32, align 4
77 %x21 = alloca i32, align 4
78 call void @"\01?two@@YAXXZ"() #3
79 store i32 2, i32* %tmp
80 %0 = bitcast i32* %tmp to i8*
81 call void (...) @llvm.localescape(i32* %x, i8* %c, i32* %x21)
82 invoke void @_CxxThrowException(i8* %0, %eh.ThrowInfo* @_TI1H) #5
83 to label %unreachable unwind label %lpad
84
85 lpad: ; preds = %entry
86 %1 = landingpad { i8*, i32 }
87 catch i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*)
88 catch %eh.CatchHandlerType* @llvm.eh.handlertype.D.0
89 catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.0
90 catch i8* null
91 %recover = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch", i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.D.0 to i8*), i32 1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch1", i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*), i32 2, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch2", i32 1, i8* null, i32 -1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch3")
92 indirectbr i8* %recover, [label %try.cont, label %try.cont10, label %try.cont22]
93
94 try.cont: ; preds = %lpad
95 call void @"\01?a@@YAXXZ"() #3
96 store i8 97, i8* %tmp2
97 invoke void @_CxxThrowException(i8* %tmp2, %eh.ThrowInfo* @_TI1D) #5
98 to label %unreachable unwind label %lpad3
99
100 lpad3: ; preds = %try.cont
101 %2 = landingpad { i8*, i32 }
102 catch %eh.CatchHandlerType* @llvm.eh.handlertype.D.0
103 catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.0
104 catch i8* null
105 %recover1 = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.D.0 to i8*), i32 1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch1", i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*), i32 2, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch2", i32 1, i8* null, i32 -1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch3")
106 indirectbr i8* %recover1, [label %try.cont10, label %try.cont22]
107
108 try.cont10: ; preds = %lpad3, %lpad
109 call void @"\01?one@@YAXXZ"() #3
110 store i32 1, i32* %tmp11
111 %3 = bitcast i32* %tmp11 to i8*
112 invoke void @_CxxThrowException(i8* %3, %eh.ThrowInfo* @_TI1H) #5
113 to label %unreachable unwind label %lpad12
114
115 lpad12: ; preds = %try.cont10
116 %4 = landingpad { i8*, i32 }
117 catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.0
118 catch i8* null
119 %recover2 = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*), i32 2, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch2", i32 1, i8* null, i32 -1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch3")
120 indirectbr i8* %recover2, [label %try.cont22]
121
122 try.cont22: ; preds = %lpad12, %lpad3, %lpad
123 ret void
124
125 unreachable: ; preds = %try.cont10, %try.cont, %entry
126 unreachable
127 }
128
129 ; Function Attrs: nounwind
130 declare void @"\01?two@@YAXXZ"() #1
131
132 declare void @_CxxThrowException(i8*, %eh.ThrowInfo*)
133
134 declare i32 @__CxxFrameHandler3(...)
135
136 ; Function Attrs: nounwind readnone
137 declare i32 @llvm.eh.typeid.for(i8*) #2
138
139 ; Function Attrs: nounwind
140 declare void @llvm.eh.begincatch(i8* nocapture, i8* nocapture) #3
141
142 ; Function Attrs: nounwind
143 declare void @"\01?catch_two@@YAXXZ"() #1
144
145 ; Function Attrs: nounwind
146 declare void @llvm.eh.endcatch() #3
147
148 ; Function Attrs: nounwind
149 declare void @"\01?a@@YAXXZ"() #1
150
151 ; Function Attrs: nounwind
152 declare void @"\01?catch_a@@YAXXZ"() #1
153
154 ; Function Attrs: nounwind
155 declare void @"\01?one@@YAXXZ"() #1
156
157 ; Function Attrs: nounwind
158 declare void @"\01?catch_all@@YAXXZ"() #1
159
160 ; Function Attrs: nounwind
161 declare void @"\01?catch_one@@YAXXZ"() #1
162
163 ; Function Attrs: nounwind
164 declare i8* @llvm.eh.actions(...) #3
165
166 define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) #4 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
167 entry:
168 %x.i8 = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0)
169 %x = bitcast i8* %x.i8 to i32*
170 %2 = bitcast i32* %x to i8*
171 call void @"\01?catch_two@@YAXXZ"() #3
172 invoke void @llvm.donothing()
173 to label %entry.split unwind label %stub
174
175 entry.split: ; preds = %entry
176 ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont)
177
178 stub: ; preds = %entry
179 %3 = landingpad { i8*, i32 }
180 cleanup
181 %recover = call i8* (...) @llvm.eh.actions()
182 unreachable
183 }
184
185 ; Function Attrs: nounwind readnone
186 declare void @llvm.donothing() #2
187
188 define internal i8* @"\01?test@@YAXXZ.catch1"(i8*, i8*) #4 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
189 entry:
190 call void @"\01?catch_a@@YAXXZ"() #3
191 invoke void @llvm.donothing()
192 to label %entry.split unwind label %stub
193
194 entry.split: ; preds = %entry
195 ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont10)
196
197 stub: ; preds = %entry
198 %2 = landingpad { i8*, i32 }
199 cleanup
200 %recover = call i8* (...) @llvm.eh.actions()
201 unreachable
202 }
203
204 define internal i8* @"\01?test@@YAXXZ.catch2"(i8*, i8*) #4 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
205 entry:
206 %x21.i8 = call i8* @llvm.localrecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 2)
207 %x21 = bitcast i8* %x21.i8 to i32*
208 %2 = bitcast i32* %x21 to i8*
209 call void @"\01?catch_one@@YAXXZ"() #3
210 invoke void @llvm.donothing()
211 to label %entry.split unwind label %stub
212
213 entry.split: ; preds = %entry
214 ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont22)
215
216 stub: ; preds = %entry
217 %3 = landingpad { i8*, i32 }
218 cleanup
219 %recover = call i8* (...) @llvm.eh.actions()
220 unreachable
221 }
222
223 define internal i8* @"\01?test@@YAXXZ.catch3"(i8*, i8*) #4 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
224 entry:
225 call void @"\01?catch_all@@YAXXZ"() #3
226 invoke void @llvm.donothing()
227 to label %entry.split unwind label %stub
228
229 entry.split: ; preds = %entry
230 ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont22)
231
232 stub: ; preds = %entry
233 %2 = landingpad { i8*, i32 }
234 cleanup
235 %recover = call i8* (...) @llvm.eh.actions()
236 unreachable
237 }
238
239 ; Function Attrs: nounwind
240 declare void @llvm.localescape(...) #3
241
242 ; Function Attrs: nounwind readnone
243 declare i8* @llvm.localrecover(i8*, i8*, i32) #2
244
245 attributes #0 = { nounwind uwtable "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-cpu"="x86-64" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" "wineh-parent"="?test@@YAXXZ" }
246 attributes #1 = { nounwind "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-cpu"="x86-64" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
247 attributes #2 = { nounwind readnone }
248 attributes #3 = { nounwind }
249 attributes #4 = { "wineh-parent"="?test@@YAXXZ" }
250 attributes #5 = { noreturn }
251
252 !llvm.module.flags = !{!0}
253 !llvm.ident = !{!1}
254
255 !0 = !{i32 1, !"PIC Level", i32 2}
256 !1 = !{!"clang version 3.7.0 (trunk 236059)"}
257
258 ; CHECK-LABEL: "$cppxdata$?test@@YAXXZ":
259 ; CHECK-NEXT: .long 429065506
260 ; CHECK-NEXT: .long
261 ; CHECK-NEXT: .long ("$stateUnwindMap$?test@@YAXXZ")@IMGREL
262 ; CHECK-NEXT: .long
263 ; CHECK-NEXT: .long ("$tryMap$?test@@YAXXZ")@IMGREL
264 ; CHECK-NEXT: .long
265 ; CHECK-NEXT: .long ("$ip2state$?test@@YAXXZ")@IMGREL
266 ; CHECK-NEXT: .long 40
267 ; CHECK-NEXT: .long 0
268 ; CHECK-NEXT: .long 1
269 ; CHECK: "$stateUnwindMap$?test@@YAXXZ":
270 ; CHECK: "$tryMap$?test@@YAXXZ":
271 ; CHECK: "$handlerMap$0$?test@@YAXXZ":
272 ; CHECK: "$ip2state$?test@@YAXXZ":
273 ; CHECK-NEXT: .long .Lfunc_begin0@IMGREL
274 ; CHECK-NEXT: .long -1
275 ; CHECK-NEXT: .long .Ltmp0@IMGREL
276 ; CHECK-NEXT: .long 2
277 ; CHECK-NEXT: .long .Ltmp3@IMGREL
278 ; CHECK-NEXT: .long 1
279 ; CHECK-NEXT: .long .Ltmp6@IMGREL
280 ; CHECK-NEXT: .long 0
281 ; CHECK-NEXT: .long .Lfunc_begin1@IMGREL
282 ; CHECK-NEXT: .long 3
283 ; CHECK-NEXT: .long .Lfunc_begin2@IMGREL
284 ; CHECK-NEXT: .long 4
285 ; CHECK-NEXT: .long .Lfunc_begin3@IMGREL
286 ; CHECK-NEXT: .long 5
287 ; CHECK-NEXT: .long .Lfunc_begin4@IMGREL
288 ; CHECK-NEXT: .long 6
+0
-29
test/CodeGen/X86/pr23900.ll less more
None ; RUN: llc -filetype=obj %s -o %t.o
1 ; RUN: llvm-nm %t.o | FileCheck %s
2
3 ; Test that it doesn't crash (and produces an object file).
4 ; This use to pass a symbol with a null name to code that expected a valid
5 ; C string.
6
7 ; CHECK: U __CxxFrameHandler3
8 ; CHECK: T f
9 ; CHECK: t f.cleanup
10 ; CHECK: U g
11 ; CHECK: U h
12
13
14 target triple = "x86_64-pc-windows-msvc18.0.0"
15 define void @f(i32 %x) personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
16 invoke void @h()
17 to label %invoke.cont unwind label %lpad
18 invoke.cont:
19 ret void
20 lpad:
21 landingpad { i8*, i32 }
22 cleanup
23 call void @g(i32 %x)
24 ret void
25 }
26 declare void @h()
27 declare i32 @__CxxFrameHandler3(...)
28 declare void @g(i32 %x)
3232 define void @f() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
3333 entry:
3434 invoke void @may_throw(i32 1)
35 to label %invoke.cont unwind label %lpad
35 to label %invoke.cont unwind label %lpad.1
3636
3737 invoke.cont: ; preds = %entry
3838 invoke void @may_throw(i32 2)
39 to label %try.cont.9 unwind label %lpad.1
39 to label %try.cont.9 unwind label %lpad
4040
4141 try.cont.9: ; preds = %invoke.cont.3, %invoke.cont, %catch.7
4242 ; FIXME: Something about our CFG breaks TailDuplication. This empy asm blocks
4545 ret void
4646
4747 lpad: ; preds = %catch, %entry
48 %0 = landingpad { i8*, i32 }
49 catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.0
50 %1 = extractvalue { i8*, i32 } %0, 0
51 %2 = extractvalue { i8*, i32 } %0, 1
52 br label %catch.dispatch.4
48 %p1 = catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
49 to label %catch unwind label %end.inner.catch
50
51 catch: ; preds = %lpad.1
52 invoke void @may_throw(i32 3)
53 to label %invoke.cont.3 unwind label %end.inner.catch
54
55 invoke.cont.3: ; preds = %catch
56 catchret %p1 to label %try.cont.9
57
58
59 end.inner.catch:
60 catchendpad unwind label %lpad.1
5361
5462 lpad.1: ; preds = %invoke.cont
55 %3 = landingpad { i8*, i32 }
56 catch i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*)
57 %4 = extractvalue { i8*, i32 } %3, 0
58 %5 = extractvalue { i8*, i32 } %3, 1
59 %6 = tail call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*)) #3
60 %matches = icmp eq i32 %5, %6
61 br i1 %matches, label %catch, label %catch.dispatch.4
63 %p2 = catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null]
64 to label %catch.7 unwind label %eh.resume
6265
63 catch.dispatch.4: ; preds = %lpad.1, %lpad
64 %exn.slot.0 = phi i8* [ %4, %lpad.1 ], [ %1, %lpad ]
65 %ehselector.slot.0 = phi i32 [ %5, %lpad.1 ], [ %2, %lpad ]
66 %.pre = tail call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*)) #3
67 %matches6 = icmp eq i32 %ehselector.slot.0, %.pre
68 br i1 %matches6, label %catch.7, label %eh.resume
66 catch.7:
67 invoke void @may_throw(i32 4)
68 to label %invoke.cont.10 unwind label %eh.resume
6969
70 catch.7: ; preds = %catch.dispatch.4
71 tail call void @llvm.eh.begincatch(i8* %exn.slot.0, i8* null) #3
72 tail call void @may_throw(i32 4)
73 tail call void @llvm.eh.endcatch() #3
74 br label %try.cont.9
75
76 catch: ; preds = %lpad.1
77 tail call void @llvm.eh.begincatch(i8* %4, i8* null) #3
78 invoke void @may_throw(i32 3)
79 to label %invoke.cont.3 unwind label %lpad
80
81 invoke.cont.3: ; preds = %catch
82 tail call void @llvm.eh.endcatch() #3
83 br label %try.cont.9
70 invoke.cont.10:
71 catchret %p2 to label %try.cont.9
8472
8573 eh.resume: ; preds = %catch.dispatch.4
86 %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn.slot.0, 0
87 %lpad.val.12 = insertvalue { i8*, i32 } %lpad.val, i32 %ehselector.slot.0, 1
88 resume { i8*, i32 } %lpad.val.12
74 catchendpad unwind to caller
8975 }
9076
9177 ; CHECK-LABEL: _f:
9985 ; CHECK: movl $1, [[state]](%ebp)
10086 ; CHECK: movl $2, (%esp)
10187 ; CHECK: calll _may_throw
102
103 ; CHECK-LABEL: _f.catch:
104 ; CHECK: movl $4, Lf$frame_escape_{{[0-9]+.*}}
88 ;
89 ; CHECK: movl $2, [[state]](%ebp)
90 ; CHECK: movl $3, (%esp)
91 ; CHECK: calll _may_throw
92 ;
93 ; CHECK: movl $3, [[state]](%ebp)
10594 ; CHECK: movl $4, (%esp)
10695 ; CHECK: calll _may_throw
10796
108 ; CHECK-LABEL: _f.catch.1:
109 ; CHECK: movl $3, Lf$frame_escape_{{[0-9]+.*}}
110 ; CHECK: movl $3, (%esp)
111 ; CHECK: calll _may_throw
112
11397 ; CHECK: .safeseh ___ehhandler$f
104104 to label %cont unwind label %catchall
105105 cont:
106106 ret void
107
107108 catchall:
108 %ehvals = landingpad { i8*, i32 }
109 catch i8* null
110 %ehptr = extractvalue { i8*, i32 } %ehvals, 0
111 call void @llvm.eh.begincatch(i8* %ehptr, i8* null)
112 call void @llvm.eh.endcatch()
113 br label %cont
109 %p = catchpad [i8* null, i32 64, i8* null]
110 to label %catch unwind label %endcatch
111
112 catch:
113 catchret %p to label %cont
114
115 endcatch:
116 catchendpad unwind to caller
114117 }
115118
116119 ; CHECK-LABEL: _use_CxxFrameHandler3: