From a6c5b9682e51553ed96706e31f51dca3f2d2abc2 Mon Sep 17 00:00:00 2001 From: Andrew Kaylor Date: Wed, 20 May 2015 23:22:24 +0000 Subject: [PATCH] [WinEH] C++ EH state numbering fixes Differential Revision: http://reviews.llvm.org/D9787 llvm-svn: 237854 --- llvm/include/llvm/CodeGen/WinEHFuncInfo.h | 4 + .../SelectionDAG/FunctionLoweringInfo.cpp | 231 +++++++++++++---- llvm/lib/CodeGen/WinEHPrepare.cpp | 239 ++++++++++++++---- llvm/test/CodeGen/WinEH/cppeh-nested-1.ll | 28 +- llvm/test/CodeGen/WinEH/cppeh-nested-2.ll | 4 +- llvm/test/CodeGen/WinEH/cppeh-nested-3.ll | 53 ++-- .../CodeGen/WinEH/cppeh-nested-rethrow.ll | 22 +- .../WinEH/cppeh-similar-catch-blocks.ll | 2 +- llvm/test/CodeGen/WinEH/cppeh-state-calc-1.ll | 14 +- 9 files changed, 428 insertions(+), 169 deletions(-) diff --git a/llvm/include/llvm/CodeGen/WinEHFuncInfo.h b/llvm/include/llvm/CodeGen/WinEHFuncInfo.h index 4efdfdf912ed..e2644edd4d12 100644 --- a/llvm/include/llvm/CodeGen/WinEHFuncInfo.h +++ b/llvm/include/llvm/CodeGen/WinEHFuncInfo.h @@ -131,6 +131,10 @@ struct WinEHTryBlockMapEntry { }; struct WinEHFuncInfo { + DenseMap RootLPad; + DenseMap LastInvoke; + DenseMap HandlerEnclosedState; + DenseMap LastInvokeVisited; DenseMap LandingPadStateMap; DenseMap CatchHandlerParentFrameObjIdx; DenseMap CatchHandlerParentFrameObjOffset; diff --git a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp index 37c58381ec21..636ed91bece4 100644 --- a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -101,7 +101,9 @@ struct WinEHNumbering { ArrayRef Handlers); void processCallSite(MutableArrayRef> Actions, ImmutableCallSite CS); + void popUnmatchedActions(int FirstMismatch); void calculateStateNumbers(const Function &F); + void findActionRootLPads(const Function &F); }; } @@ -297,9 +299,16 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf, EHInfo = &MMI.getWinEHFuncInfo(WinEHParentFn); if (EHInfo->LandingPadStateMap.empty()) { WinEHNumbering Num(*EHInfo); + Num.findActionRootLPads(*WinEHParentFn); + // The VisitedHandlers list is used by both findActionRootLPads and + // calculateStateNumbers, but both functions need to visit all handlers. + Num.VisitedHandlers.clear(); Num.calculateStateNumbers(*WinEHParentFn); // Pop everything on the handler stack. - Num.processCallSite(None, ImmutableCallSite()); + // It may be necessary to call this more than once because a handler can + // be pushed on the stack as a result of clearing the stack. + while (!Num.HandlerStack.empty()) + Num.processCallSite(None, ImmutableCallSite()); } // Copy the state numbers to LandingPadInfo for the current function, which @@ -361,6 +370,45 @@ void WinEHNumbering::createUnwindMapEntry(int ToState, ActionHandler *AH) { void WinEHNumbering::createTryBlockMapEntry(int TryLow, int TryHigh, ArrayRef Handlers) { + // See if we already have an entry for this set of handlers. + // This is using iterators rather than a range-based for loop because + // if we find the entry we're looking for we'll need the iterator to erase it. + int NumHandlers = Handlers.size(); + auto I = FuncInfo.TryBlockMap.begin(); + auto E = FuncInfo.TryBlockMap.end(); + for ( ; I != E; ++I) { + auto &Entry = *I; + if (Entry.HandlerArray.size() != NumHandlers) + continue; + int N; + for (N = 0; N < NumHandlers; ++N) { + if (Entry.HandlerArray[N].Handler != Handlers[N]->getHandlerBlockOrFunc()) + break; // breaks out of inner loop + } + // If all the handlers match, this is what we were looking for. + if (N == NumHandlers) { + break; + } + } + + // If we found an existing entry for this set of handlers, extend the range + // but move the entry to the end of the map vector. The order of entries + // in the map is critical to the way that the runtime finds handlers. + // FIXME: Depending on what has happened with block ordering, this may + // incorrectly combine entries that should remain separate. + if (I != E) { + // Copy the existing entry. + WinEHTryBlockMapEntry Entry = *I; + Entry.TryLow = std::min(TryLow, Entry.TryLow); + Entry.TryHigh = std::max(TryHigh, Entry.TryHigh); + assert(Entry.TryLow <= Entry.TryHigh); + // Erase the old entry and add this one to the back. + FuncInfo.TryBlockMap.erase(I); + FuncInfo.TryBlockMap.push_back(Entry); + return; + } + + // If we didn't find an entry, create a new one. WinEHTryBlockMapEntry TBME; TBME.TryLow = TryLow; TBME.TryHigh = TryHigh; @@ -429,6 +477,65 @@ void WinEHNumbering::processCallSite( break; } + // Remove unmatched actions from the stack and process their EH states. + popUnmatchedActions(FirstMismatch); + + DEBUG(dbgs() << "Pushing actions for CallSite: "); + print_name(CS ? CS.getCalledValue() : nullptr); + DEBUG(dbgs() << '\n'); + + bool LastActionWasCatch = false; + const LandingPadInst *LastRootLPad = nullptr; + for (size_t I = FirstMismatch; I != Actions.size(); ++I) { + // We can reuse eh states when pushing two catches for the same invoke. + bool CurrActionIsCatch = isa(Actions[I].get()); + auto *Handler = cast(Actions[I]->getHandlerBlockOrFunc()); + // Various conditions can lead to a handler being popped from the + // stack and re-pushed later. That shouldn't create a new state. + // FIXME: Can code optimization lead to re-used handlers? + if (FuncInfo.HandlerEnclosedState.count(Handler)) { + // If we already assigned the state enclosed by this handler re-use it. + Actions[I]->setEHState(FuncInfo.HandlerEnclosedState[Handler]); + continue; + } + const LandingPadInst* RootLPad = FuncInfo.RootLPad[Handler]; + if (CurrActionIsCatch && LastActionWasCatch && RootLPad == LastRootLPad) { + DEBUG(dbgs() << "setEHState for handler to " << currentEHNumber() << "\n"); + Actions[I]->setEHState(currentEHNumber()); + } else { + DEBUG(dbgs() << "createUnwindMapEntry(" << currentEHNumber() << ", "); + print_name(Actions[I]->getHandlerBlockOrFunc()); + DEBUG(dbgs() << ") with EH state " << NextState << "\n"); + createUnwindMapEntry(currentEHNumber(), Actions[I].get()); + DEBUG(dbgs() << "setEHState for handler to " << NextState << "\n"); + Actions[I]->setEHState(NextState); + NextState++; + } + HandlerStack.push_back(std::move(Actions[I])); + LastActionWasCatch = CurrActionIsCatch; + LastRootLPad = RootLPad; + } + + // This is used to defer numbering states for a handler until after the + // last time it appears in an invoke action list. + if (CS.isInvoke()) { + for (int I = 0, E = HandlerStack.size(); I < E; ++I) { + auto *Handler = cast(HandlerStack[I]->getHandlerBlockOrFunc()); + if (FuncInfo.LastInvoke[Handler] != cast(CS.getInstruction())) + continue; + FuncInfo.LastInvokeVisited[Handler] = true; + DEBUG(dbgs() << "Last invoke of "); + print_name(Handler); + DEBUG(dbgs() << " has been visited.\n"); + } + } + + DEBUG(dbgs() << "In EHState " << currentEHNumber() << " for CallSite: "); + print_name(CS ? CS.getCalledValue() : nullptr); + DEBUG(dbgs() << '\n'); +} + +void WinEHNumbering::popUnmatchedActions(int FirstMismatch) { // Don't recurse while we are looping over the handler stack. Instead, defer // the numbering of the catch handlers until we are done popping. SmallVector PoppedCatches; @@ -460,60 +567,25 @@ void WinEHNumbering::processCallSite( for (CatchHandler *CH : PoppedCatches) { if (auto *F = dyn_cast(CH->getHandlerBlockOrFunc())) { - DEBUG(dbgs() << "Assigning base state " << NextState << " to "); - print_name(F); - DEBUG(dbgs() << '\n'); - FuncInfo.HandlerBaseState[F] = NextState; - DEBUG(dbgs() << "createUnwindMapEntry(" << currentEHNumber() - << ", null)\n"); - createUnwindMapEntry(currentEHNumber(), nullptr); - ++NextState; - calculateStateNumbers(*F); + if (FuncInfo.LastInvokeVisited[F]) { + DEBUG(dbgs() << "Assigning base state " << NextState << " to "); + print_name(F); + DEBUG(dbgs() << '\n'); + FuncInfo.HandlerBaseState[F] = NextState; + DEBUG(dbgs() << "createUnwindMapEntry(" << currentEHNumber() + << ", null)\n"); + createUnwindMapEntry(currentEHNumber(), nullptr); + ++NextState; + calculateStateNumbers(*F); + } + else { + DEBUG(dbgs() << "Deferring handling of "); + print_name(F); + DEBUG(dbgs() << " until last invoke visited.\n"); + } } delete CH; } - - // The handler functions may have pushed actions onto the handler stack - // that we expected to push here. Compare the handler stack to our - // actions again to check for that possibility. - if (HandlerStack.size() > (size_t)FirstMismatch) { - for (int E = std::min(HandlerStack.size(), Actions.size()); - FirstMismatch < E; ++FirstMismatch) { - if (HandlerStack[FirstMismatch]->getHandlerBlockOrFunc() != - Actions[FirstMismatch]->getHandlerBlockOrFunc()) - break; - } - } - - DEBUG(dbgs() << "Pushing actions for CallSite: "); - print_name(CS ? CS.getCalledValue() : nullptr); - DEBUG(dbgs() << '\n'); - - bool LastActionWasCatch = false; - for (size_t I = FirstMismatch; I != Actions.size(); ++I) { - // We can reuse eh states when pushing two catches for the same invoke. - bool CurrActionIsCatch = isa(Actions[I].get()); - // FIXME: Reenable this optimization! - if (CurrActionIsCatch && LastActionWasCatch && false) { - DEBUG(dbgs() << "setEHState for handler to " << currentEHNumber() - << "\n"); - Actions[I]->setEHState(currentEHNumber()); - } else { - DEBUG(dbgs() << "createUnwindMapEntry(" << currentEHNumber() << ", "); - print_name(Actions[I]->getHandlerBlockOrFunc()); - DEBUG(dbgs() << ")\n"); - createUnwindMapEntry(currentEHNumber(), Actions[I].get()); - DEBUG(dbgs() << "setEHState for handler to " << NextState << "\n"); - Actions[I]->setEHState(NextState); - NextState++; - } - HandlerStack.push_back(std::move(Actions[I])); - LastActionWasCatch = CurrActionIsCatch; - } - - DEBUG(dbgs() << "In EHState " << currentEHNumber() << " for CallSite: "); - print_name(CS ? CS.getCalledValue() : nullptr); - DEBUG(dbgs() << '\n'); } void WinEHNumbering::calculateStateNumbers(const Function &F) { @@ -526,6 +598,8 @@ void WinEHNumbering::calculateStateNumbers(const Function &F) { CurrentBaseState = FuncInfo.HandlerBaseState[&F]; } + size_t SavedHandlerStackSize = HandlerStack.size(); + DEBUG(dbgs() << "Calculating state numbers for: " << F.getName() << '\n'); SmallVector, 4> ActionList; for (const BasicBlock &BB : F) { @@ -554,11 +628,64 @@ void WinEHNumbering::calculateStateNumbers(const Function &F) { << '\n'); } + // Pop any actions that were pushed on the stack for this function. + popUnmatchedActions(SavedHandlerStackSize); + + DEBUG(dbgs() << "Assigning max state " << NextState - 1 + << " to " << F.getName() << '\n'); FuncInfo.CatchHandlerMaxState[&F] = NextState - 1; CurrentBaseState = OldBaseState; } +// This function follows the same basic traversal as calculateStateNumbers +// but it is necessary to identify the root landing pad associated +// with each action before we start assigning state numbers. +void WinEHNumbering::findActionRootLPads(const Function &F) { + auto I = VisitedHandlers.insert(&F); + if (!I.second) + return; // We've already visited this handler, don't revisit it. + + SmallVector, 4> ActionList; + for (const BasicBlock &BB : F) { + const auto *II = dyn_cast(BB.getTerminator()); + if (!II) + continue; + const LandingPadInst *LPI = II->getLandingPadInst(); + auto *ActionsCall = dyn_cast(LPI->getNextNode()); + if (!ActionsCall) + continue; + + assert(ActionsCall->getIntrinsicID() == Intrinsic::eh_actions); + parseEHActions(ActionsCall, ActionList); + if (ActionList.empty()) + continue; + for (int I = 0, E = ActionList.size(); I < E; ++I) { + if (auto *Handler + = dyn_cast(ActionList[I]->getHandlerBlockOrFunc())) { + FuncInfo.LastInvoke[Handler] = II; + // Don't replace the root landing pad if we previously saw this + // handler in a different function. + if (FuncInfo.RootLPad.count(Handler) && + FuncInfo.RootLPad[Handler]->getParent()->getParent() != &F) + continue; + DEBUG(dbgs() << "Setting root lpad for "); + print_name(Handler); + DEBUG(dbgs() << " to " << LPI->getParent()->getName() << '\n'); + FuncInfo.RootLPad[Handler] = LPI; + } + } + // Walk the actions again and look for nested handlers. This has to + // happen after all of the actions have been processed in the current + // function. + for (int I = 0, E = ActionList.size(); I < E; ++I) + if (auto *Handler + = dyn_cast(ActionList[I]->getHandlerBlockOrFunc())) + findActionRootLPads(*Handler); + ActionList.clear(); + } +} + /// clear - Clear out all the function-specific state. This returns this /// FunctionLoweringInfo to an empty state, ready to be used for a /// different function. diff --git a/llvm/lib/CodeGen/WinEHPrepare.cpp b/llvm/lib/CodeGen/WinEHPrepare.cpp index e4e63fddebb8..8f67d21a47d9 100644 --- a/llvm/lib/CodeGen/WinEHPrepare.cpp +++ b/llvm/lib/CodeGen/WinEHPrepare.cpp @@ -91,6 +91,7 @@ public: private: bool prepareExceptionHandlers(Function &F, SmallVectorImpl &LPads); + void identifyEHBlocks(Function &F, SmallVectorImpl &LPads); void promoteLandingPadValues(LandingPadInst *LPad); void demoteValuesLiveAcrossHandlers(Function &F, SmallVectorImpl &LPads); @@ -127,6 +128,9 @@ private: CatchHandlerMapTy CatchHandlerMap; CleanupHandlerMapTy CleanupHandlerMap; DenseMap LPadMaps; + SmallPtrSet NormalBlocks; + SmallPtrSet EHBlocks; + SetVector EHReturnBlocks; // This maps landing pad instructions found in outlined handlers to // the landing pad instruction in the parent function from which they @@ -214,6 +218,9 @@ public: virtual CloningAction handleTypeIdFor(ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) = 0; + virtual CloningAction handleIndirectBr(ValueToValueMapTy &VMap, + const IndirectBrInst *IBr, + BasicBlock *NewBB) = 0; virtual CloningAction handleInvoke(ValueToValueMapTy &VMap, const InvokeInst *Invoke, BasicBlock *NewBB) = 0; @@ -244,10 +251,12 @@ public: WinEHCatchDirector( Function *CatchFn, Value *ParentFP, Value *Selector, FrameVarInfoMap &VarInfo, LandingPadMap &LPadMap, - DenseMap &NestedLPads) + DenseMap &NestedLPads, + DominatorTree *DT, SmallPtrSetImpl &EHBlocks) : WinEHCloningDirectorBase(CatchFn, ParentFP, VarInfo, LPadMap), CurrentSelector(Selector->stripPointerCasts()), - ExceptionObjectVar(nullptr), NestedLPtoOriginalLP(NestedLPads) {} + ExceptionObjectVar(nullptr), NestedLPtoOriginalLP(NestedLPads), + DT(DT), EHBlocks(EHBlocks) {} CloningAction handleBeginCatch(ValueToValueMapTy &VMap, const Instruction *Inst, @@ -257,6 +266,9 @@ public: CloningAction handleTypeIdFor(ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) override; + CloningAction handleIndirectBr(ValueToValueMapTy &VMap, + const IndirectBrInst *IBr, + BasicBlock *NewBB) override; CloningAction handleInvoke(ValueToValueMapTy &VMap, const InvokeInst *Invoke, BasicBlock *NewBB) override; CloningAction handleResume(ValueToValueMapTy &VMap, const ResumeInst *Resume, @@ -279,6 +291,8 @@ private: // This will be a reference to the field of the same name in the WinEHPrepare // object which instantiates this WinEHCatchDirector object. DenseMap &NestedLPtoOriginalLP; + DominatorTree *DT; + SmallPtrSetImpl &EHBlocks; }; class WinEHCleanupDirector : public WinEHCloningDirectorBase { @@ -296,6 +310,9 @@ public: CloningAction handleTypeIdFor(ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) override; + CloningAction handleIndirectBr(ValueToValueMapTy &VMap, + const IndirectBrInst *IBr, + BasicBlock *NewBB) override; CloningAction handleInvoke(ValueToValueMapTy &VMap, const InvokeInst *Invoke, BasicBlock *NewBB) override; CloningAction handleResume(ValueToValueMapTy &VMap, const ResumeInst *Resume, @@ -525,13 +542,8 @@ void WinEHPrepare::findSEHEHReturnPoints( } } -/// Ensure that all values live into and out of exception handlers are stored -/// in memory. -/// FIXME: This falls down when values are defined in one handler and live into -/// another handler. For example, a cleanup defines a value used only by a -/// catch handler. -void WinEHPrepare::demoteValuesLiveAcrossHandlers( - Function &F, SmallVectorImpl &LPads) { +void WinEHPrepare::identifyEHBlocks(Function &F, + SmallVectorImpl &LPads) { DEBUG(dbgs() << "Demoting values live across exception handlers in function " << F.getName() << '\n'); @@ -541,10 +553,6 @@ void WinEHPrepare::demoteValuesLiveAcrossHandlers( // - Exceptional blocks are blocks reachable from landingpads. Analysis does // not follow llvm.eh.endcatch blocks, which mark a transition from // exceptional to normal control. - SmallPtrSet NormalBlocks; - SmallPtrSet EHBlocks; - SetVector EHReturnBlocks; - SetVector Worklist; if (Personality == EHPersonality::MSVC_CXX) findCXXEHReturnPoints(F, EHReturnBlocks); @@ -567,6 +575,7 @@ void WinEHPrepare::demoteValuesLiveAcrossHandlers( // Normal blocks are the blocks reachable from the entry block and all EH // return points. + SetVector Worklist; Worklist = EHReturnBlocks; Worklist.insert(&F.getEntryBlock()); findReachableBlocks(NormalBlocks, Worklist, nullptr); @@ -588,6 +597,21 @@ void WinEHPrepare::demoteValuesLiveAcrossHandlers( dbgs() << " " << BB->getName() << '\n'; }); +} + +/// Ensure that all values live into and out of exception handlers are stored +/// in memory. +/// FIXME: This falls down when values are defined in one handler and live into +/// another handler. For example, a cleanup defines a value used only by a +/// catch handler. +void WinEHPrepare::demoteValuesLiveAcrossHandlers( + Function &F, SmallVectorImpl &LPads) { + DEBUG(dbgs() << "Demoting values live across exception handlers in function " + << F.getName() << '\n'); + + // identifyEHBlocks() should have been called before this function. + assert(!NormalBlocks.empty()); + SetVector ArgsToDemote; SetVector InstrsToDemote; for (BasicBlock &BB : F) { @@ -678,6 +702,7 @@ bool WinEHPrepare::prepareExceptionHandlers( return false; } + identifyEHBlocks(F, LPads); demoteValuesLiveAcrossHandlers(F, LPads); // These containers are used to re-map frame variables that are used in @@ -702,6 +727,16 @@ bool WinEHPrepare::prepareExceptionHandlers( F.getEntryBlock().getFirstInsertionPt()); } + // In order to handle the case where one outlined catch handler returns + // to a block within another outlined catch handler that would otherwise + // be unreachable, we need to outline the nested landing pad before we + // outline the landing pad which encloses it. + if (!isAsynchronousEHPersonality(Personality)) + std::sort(LPads.begin(), LPads.end(), + [this](LandingPadInst* &L, LandingPadInst* &R) { + return DT->dominates(R->getParent(), L->getParent()); + }); + // This container stores the llvm.eh.recover and IndirectBr instructions // that make up the body of each landing pad after it has been outlined. // We need to defer the population of the target list for the indirectbr @@ -829,28 +864,24 @@ bool WinEHPrepare::prepareExceptionHandlers( CallInst *Recover = CallInst::Create(ActionIntrin, ActionArgs, "recover", LPadBB); - if (isAsynchronousEHPersonality(Personality)) { - // SEH can create the target list directly, since catch handlers - // are not outlined. - SetVector ReturnTargets; - for (ActionHandler *Action : Actions) { - if (auto *CatchAction = dyn_cast(Action)) { - const auto &CatchTargets = CatchAction->getReturnTargets(); - ReturnTargets.insert(CatchTargets.begin(), CatchTargets.end()); - } + SetVector ReturnTargets; + for (ActionHandler *Action : Actions) { + if (auto *CatchAction = dyn_cast(Action)) { + const auto &CatchTargets = CatchAction->getReturnTargets(); + ReturnTargets.insert(CatchTargets.begin(), CatchTargets.end()); } - IndirectBrInst *Branch = - IndirectBrInst::Create(Recover, ReturnTargets.size(), LPadBB); - for (BasicBlock *Target : ReturnTargets) - Branch->addDestination(Target); - } else { - // C++ EH must defer populating the targets to handle the case of - // targets that are reached indirectly through nested landing pads. - IndirectBrInst *Branch = - IndirectBrInst::Create(Recover, 0, LPadBB); + } + IndirectBrInst *Branch = + IndirectBrInst::Create(Recover, ReturnTargets.size(), LPadBB); + for (BasicBlock *Target : ReturnTargets) + Branch->addDestination(Target); + if (!isAsynchronousEHPersonality(Personality)) { + // C++ EH must repopulate the targets later to handle the case of + // targets that are reached indirectly through nested landing pads. LPadImpls.push_back(std::make_pair(Recover, Branch)); } + } // End for each landingpad // If nothing got outlined, there is no more processing to be done. @@ -864,8 +895,7 @@ bool WinEHPrepare::prepareExceptionHandlers( completeNestedLandingPad(&F, LPadPair.first, LPadPair.second, FrameVarInfo); NestedLPtoOriginalLP.clear(); - // Populate the indirectbr instructions' target lists if we deferred - // doing so above. + // Update the indirectbr instructions' target lists if necessary. SetVector CheckedTargets; SmallVector, 4> ActionList; for (auto &LPadImplPair : LPadImpls) { @@ -884,6 +914,12 @@ bool WinEHPrepare::prepareExceptionHandlers( } } ActionList.clear(); + // Clear any targets we already knew about. + for (unsigned int I = 0, E = Branch->getNumDestinations(); I < E; ++I) { + BasicBlock *KnownTarget = Branch->getDestination(I); + if (ReturnTargets.count(KnownTarget)) + ReturnTargets.remove(KnownTarget); + } for (BasicBlock *Target : ReturnTargets) { Branch->addDestination(Target); // The target may be a block that we excepted to get pruned. @@ -994,6 +1030,9 @@ bool WinEHPrepare::prepareExceptionHandlers( HandlerToParentFP.clear(); DT = nullptr; SEHExceptionCodeSlot = nullptr; + EHBlocks.clear(); + NormalBlocks.clear(); + EHReturnBlocks.clear(); return HandlersOutlined; } @@ -1079,10 +1118,19 @@ void WinEHPrepare::completeNestedLandingPad(Function *ParentFn, // temporarily inserted as its terminator. LLVMContext &Context = ParentFn->getContext(); BasicBlock *OutlinedBB = OutlinedLPad->getParent(); - assert(isa(OutlinedBB->getTerminator())); - OutlinedBB->getTerminator()->eraseFromParent(); - // That should leave OutlinedLPad as the last instruction in its block. - assert(&OutlinedBB->back() == OutlinedLPad); + // If the nested landing pad was outlined before the landing pad that enclosed + // it, it will already be in outlined form. In that case, we just need to see + // if the returns and the enclosing branch instruction need to be updated. + IndirectBrInst *Branch = + dyn_cast(OutlinedBB->getTerminator()); + if (!Branch) { + // If the landing pad wasn't in outlined form, it should be a stub with + // an unreachable terminator. + assert(isa(OutlinedBB->getTerminator())); + OutlinedBB->getTerminator()->eraseFromParent(); + // That should leave OutlinedLPad as the last instruction in its block. + assert(&OutlinedBB->back() == OutlinedLPad); + } // The original landing pad will have already had its action intrinsic // built by the outlining loop. We need to clone that into the outlined @@ -1096,9 +1144,9 @@ void WinEHPrepare::completeNestedLandingPad(Function *ParentFn, // The instruction after the landing pad should now be a call to eh.actions. const Instruction *Recover = II; assert(match(Recover, m_Intrinsic())); - IntrinsicInst *EHActions = cast(Recover->clone()); + const IntrinsicInst *EHActions = cast(Recover); - // Remap the exception variables into the outlined function. + // Remap the return target in the nested handler. SmallVector ActionTargets; SmallVector, 4> ActionList; parseEHActions(EHActions, ActionList); @@ -1125,7 +1173,7 @@ void WinEHPrepare::completeNestedLandingPad(Function *ParentFn, // should be a block that was outlined into OutlinedHandlerFn. assert(BA->getFunction() == ParentFn); - // Ignore targets that aren't part of OutlinedHandlerFn. + // Ignore targets that aren't part of an outlined handler function. if (!LPadTargetBlocks.count(BA->getBasicBlock())) continue; @@ -1142,13 +1190,25 @@ void WinEHPrepare::completeNestedLandingPad(Function *ParentFn, } } ActionList.clear(); - OutlinedBB->getInstList().push_back(EHActions); - // Insert an indirect branch into the outlined landing pad BB. - IndirectBrInst *IBr = IndirectBrInst::Create(EHActions, 0, OutlinedBB); - // Add the previously collected action targets. - for (auto *Target : ActionTargets) - IBr->addDestination(Target->getBasicBlock()); + if (Branch) { + // If the landing pad was already in outlined form, just update its targets. + for (unsigned int I = Branch->getNumDestinations(); I > 0; --I) + Branch->removeDestination(I); + // Add the previously collected action targets. + for (auto *Target : ActionTargets) + Branch->addDestination(Target->getBasicBlock()); + } else { + // If the landing pad was previously stubbed out, fill in its outlined form. + IntrinsicInst *NewEHActions = cast(EHActions->clone()); + OutlinedBB->getInstList().push_back(NewEHActions); + + // Insert an indirect branch into the outlined landing pad BB. + IndirectBrInst *IBr = IndirectBrInst::Create(NewEHActions, 0, OutlinedBB); + // Add the previously collected action targets. + for (auto *Target : ActionTargets) + IBr->addDestination(Target->getBasicBlock()); + } } // This function examines a block to determine whether the block ends with a @@ -1326,9 +1386,9 @@ bool WinEHPrepare::outlineHandler(ActionHandler *Action, Function *SrcFn, LPadMap.mapLandingPad(LPad); if (auto *CatchAction = dyn_cast(Action)) { Constant *Sel = CatchAction->getSelector(); - Director.reset(new WinEHCatchDirector(Handler, ParentFP, Sel, - VarInfo, LPadMap, - NestedLPtoOriginalLP)); + Director.reset(new WinEHCatchDirector(Handler, ParentFP, Sel, VarInfo, + LPadMap, NestedLPtoOriginalLP, DT, + EHBlocks)); LPadMap.remapEHValues(VMap, UndefValue::get(Int8PtrType), ConstantInt::get(Type::getInt32Ty(Context), 1)); } else { @@ -1532,15 +1592,22 @@ CloningDirector::CloningAction WinEHCloningDirectorBase::handleInstruction( if (LPadMap.isLandingPadSpecificInst(Inst)) return CloningDirector::SkipInstruction; - // Nested landing pads will be cloned as stubs, with just the - // landingpad instruction and an unreachable instruction. When - // all landingpads have been outlined, we'll replace this with the - // llvm.eh.actions call and indirect branch created when the - // landing pad was outlined. + // Nested landing pads that have not already been outlined will be cloned as + // stubs, with just the landingpad instruction and an unreachable instruction. + // When all landingpads have been outlined, we'll replace this with the + // llvm.eh.actions call and indirect branch created when the landing pad was + // outlined. if (auto *LPad = dyn_cast(Inst)) { return handleLandingPad(VMap, LPad, NewBB); } + // Nested landing pads that have already been outlined will be cloned in their + // outlined form, but we need to intercept the ibr instruction to filter out + // targets that do not return to the handler we are outlining. + if (auto *IBr = dyn_cast(Inst)) { + return handleIndirectBr(VMap, IBr, NewBB); + } + if (auto *Invoke = dyn_cast(Inst)) return handleInvoke(VMap, Invoke, NewBB); @@ -1570,6 +1637,20 @@ CloningDirector::CloningAction WinEHCloningDirectorBase::handleInstruction( CloningDirector::CloningAction WinEHCatchDirector::handleLandingPad( ValueToValueMapTy &VMap, const LandingPadInst *LPad, BasicBlock *NewBB) { + // If the instruction after the landing pad is a call to llvm.eh.actions + // the landing pad has already been outlined. In this case, we should + // clone it because it may return to a block in the handler we are + // outlining now that would otherwise be unreachable. The landing pads + // are sorted before outlining begins to enable this case to work + // properly. + const Instruction *NextI = LPad->getNextNode(); + if (match(NextI, m_Intrinsic())) + return CloningDirector::CloneInstruction; + + // If the landing pad hasn't been outlined yet, the landing pad we are + // outlining now does not dominate it and so it cannot return to a block + // in this handler. In that case, we can just insert a stub landing + // pad now and patch it up later. Instruction *NewInst = LPad->clone(); if (LPad->hasName()) NewInst->setName(LPad->getName()); @@ -1661,6 +1742,48 @@ CloningDirector::CloningAction WinEHCatchDirector::handleTypeIdFor( return CloningDirector::SkipInstruction; } +CloningDirector::CloningAction WinEHCatchDirector::handleIndirectBr( + ValueToValueMapTy &VMap, + const IndirectBrInst *IBr, + BasicBlock *NewBB) { + // If this indirect branch is not part of a landing pad block, just clone it. + const BasicBlock *ParentBB = IBr->getParent(); + if (!ParentBB->isLandingPad()) + return CloningDirector::CloneInstruction; + + // If it is part of a landing pad, we want to filter out target blocks + // that are not part of the handler we are outlining. + const LandingPadInst *LPad = ParentBB->getLandingPadInst(); + + // Save this correlation for later processing. + NestedLPtoOriginalLP[cast(VMap[LPad])] = LPad; + + // We should only get here for landing pads that have already been outlined. + assert(match(LPad->getNextNode(), m_Intrinsic())); + + // Copy the indirectbr, but only include targets that were previously + // identified as EH blocks and are dominated by the nested landing pad. + SetVector ReturnTargets; + for (int I = 0, E = IBr->getNumDestinations(); I < E; ++I) { + auto *TargetBB = IBr->getDestination(I); + if (EHBlocks.count(const_cast(TargetBB)) && + DT->dominates(ParentBB, TargetBB)) { + DEBUG(dbgs() << " Adding destination " << TargetBB->getName() << "\n"); + ReturnTargets.insert(TargetBB); + } + } + IndirectBrInst *NewBranch = + IndirectBrInst::Create(const_cast(IBr->getAddress()), + ReturnTargets.size(), NewBB); + for (auto *Target : ReturnTargets) + NewBranch->addDestination(const_cast(Target)); + + // The operands and targets of the branch instruction are remapped later + // because it is a terminator. Tell the cloning code to clone the + // blocks we just added to the target list. + return CloningDirector::CloneSuccessors; +} + CloningDirector::CloningAction WinEHCatchDirector::handleInvoke(ValueToValueMapTy &VMap, const InvokeInst *Invoke, BasicBlock *NewBB) { @@ -1750,6 +1873,14 @@ CloningDirector::CloningAction WinEHCleanupDirector::handleTypeIdFor( return CloningDirector::SkipInstruction; } +CloningDirector::CloningAction WinEHCleanupDirector::handleIndirectBr( + ValueToValueMapTy &VMap, + const IndirectBrInst *IBr, + BasicBlock *NewBB) { + // No special handling is required for cleanup cloning. + return CloningDirector::CloneInstruction; +} + CloningDirector::CloningAction WinEHCleanupDirector::handleInvoke( ValueToValueMapTy &VMap, const InvokeInst *Invoke, BasicBlock *NewBB) { // All invokes in cleanup handlers can be replaced with calls. diff --git a/llvm/test/CodeGen/WinEH/cppeh-nested-1.ll b/llvm/test/CodeGen/WinEH/cppeh-nested-1.ll index 871ec6aed288..2b13510c5745 100644 --- a/llvm/test/CodeGen/WinEH/cppeh-nested-1.ll +++ b/llvm/test/CodeGen/WinEH/cppeh-nested-1.ll @@ -34,7 +34,7 @@ $"\01??_R0H@8" = comdat any ; CHECK: entry: ; CHECK: %i = alloca i32, align 4 ; CHECK: %f = alloca float, align 4 -; CHECK: call void (...) @llvm.frameescape(i32* %i, float* %f) +; CHECK: call void (...) @llvm.frameescape(float* %f, i32* %i) ; CHECK: invoke void @"\01?may_throw@@YAXXZ"() ; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]*]] @@ -55,8 +55,8 @@ invoke.cont: ; preds = %entry ; CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) ; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) ; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*) -; CHECK: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch", i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.1") -; CHECK: indirectbr i8* [[RECOVER]], [label %try.cont10, label %try.cont] +; CHECK: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.1", i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch") +; CHECK: indirectbr i8* [[RECOVER]], [label %try.cont, label %try.cont10] lpad: ; preds = %entry %0 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) @@ -136,7 +136,16 @@ eh.resume: ; %catch.dispatch3 ; CHECK: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) ; CHECK: entry: -; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0) +; CHECK: [[RECOVER_F1:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0) +; CHECK: [[F_PTR1:\%.+]] = bitcast i8* [[RECOVER_F1]] to float* +; CHECK: [[TMP2:\%.+]] = load float, float* [[F_PTR1]], align 4 +; CHECK: call void @"\01?handle_float@@YAXM@Z"(float [[TMP2]]) +; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont10) +; CHECK: } + +; CHECK: define internal i8* @"\01?test@@YAXXZ.catch.1"(i8*, i8*) +; CHECK: entry: +; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1) ; CHECK: [[I_PTR:\%.+]] = bitcast i8* [[RECOVER_I]] to i32* ; CHECK: [[TMP1:\%.+]] = load i32, i32* [[I_PTR]], align 4 ; CHECK: invoke void @"\01?handle_int@@YAXH@Z"(i32 [[TMP1]]) @@ -148,20 +157,11 @@ eh.resume: ; %catch.dispatch3 ; CHECK: [[LPAD1_LABEL]]:{{[ ]+}}; preds = %entry ; CHECK: [[LPAD1_VAL:\%.+]] = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) ; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*) -; CHECK: [[RECOVER1:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.1") +; CHECK: [[RECOVER1:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch") ; CHECK: indirectbr i8* [[RECOVER1]], [] ; ; CHECK: } -; CHECK: define internal i8* @"\01?test@@YAXXZ.catch.1"(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_F1:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1) -; CHECK: [[F_PTR1:\%.+]] = bitcast i8* [[RECOVER_F1]] to float* -; CHECK: [[TMP2:\%.+]] = load float, float* [[F_PTR1]], align 4 -; CHECK: call void @"\01?handle_float@@YAXM@Z"(float [[TMP2]]) -; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont10) -; CHECK: } - declare void @"\01?may_throw@@YAXXZ"() #1 diff --git a/llvm/test/CodeGen/WinEH/cppeh-nested-2.ll b/llvm/test/CodeGen/WinEH/cppeh-nested-2.ll index d803adb808b5..f12f3dbed085 100644 --- a/llvm/test/CodeGen/WinEH/cppeh-nested-2.ll +++ b/llvm/test/CodeGen/WinEH/cppeh-nested-2.ll @@ -114,7 +114,7 @@ lpad: ; preds = %try.cont, %entry ; CHECK-SAME: i32 1, i8* bitcast (i8** @_ZTIi to i8*), i32 1, i8* (i8*, i8*)* @_Z4testv.catch.1, ; CHECK-SAME: i32 0, void (i8*, i8*)* @_Z4testv.cleanup, ; CHECK-SAME: i32 1, i8* bitcast (i8** @_ZTIf to i8*), i32 0, i8* (i8*, i8*)* @_Z4testv.catch) -; CHECK-NEXT: indirectbr i8* [[RECOVER1]], [label %try.cont19, label %try.cont] +; CHECK-NEXT: indirectbr i8* [[RECOVER1]], [label %try.cont, label %try.cont19] lpad1: ; preds = %invoke.cont4, %invoke.cont %tmp3 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) @@ -137,7 +137,7 @@ lpad1: ; preds = %invoke.cont4, %invo ; CHECK-SAME: i32 1, i8* bitcast (i8** @_ZTIi to i8*), i32 1, i8* (i8*, i8*)* @_Z4testv.catch.1, ; CHECK-SAME: i32 0, void (i8*, i8*)* @_Z4testv.cleanup, ; CHECK-SAME: i32 1, i8* bitcast (i8** @_ZTIf to i8*), i32 0, i8* (i8*, i8*)* @_Z4testv.catch) -; CHECK-NEXT: indirectbr i8* [[RECOVER3]], [label %try.cont19, label %try.cont] +; CHECK-NEXT: indirectbr i8* [[RECOVER3]], [label %try.cont, label %try.cont19] lpad3: ; preds = %invoke.cont2 %tmp6 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) diff --git a/llvm/test/CodeGen/WinEH/cppeh-nested-3.ll b/llvm/test/CodeGen/WinEH/cppeh-nested-3.ll index dd8a5f6a474c..c96abcc6e81c 100644 --- a/llvm/test/CodeGen/WinEH/cppeh-nested-3.ll +++ b/llvm/test/CodeGen/WinEH/cppeh-nested-3.ll @@ -41,7 +41,7 @@ $"\01??_R0H@8" = comdat any ; CHECK: %i = alloca i32, align 4 ; CHECK: %j = alloca i32, align 4 ; CHECK: %f = alloca float, align 4 -; CHECK: call void (...) @llvm.frameescape(i32* %i, float* %f, i32* %j) +; CHECK: call void (...) @llvm.frameescape(i32* %j, i32* %i, float* %f) ; CHECK: invoke void @"\01?may_throw@@YAXXZ"() ; CHECK: to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]*]] @@ -63,8 +63,8 @@ invoke.cont: ; preds = %entry ; CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) ; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) ; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*) -; CHECK: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch", i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.1") -; CHECK: indirectbr i8* [[RECOVER]], [label %try.cont19, label %try.cont10] +; CHECK: [[RECOVER:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.2", i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 2, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.1") +; CHECK: indirectbr i8* [[RECOVER]], [label %try.cont10, label %try.cont19] lpad: ; preds = %entry %0 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) @@ -181,7 +181,27 @@ eh.resume: ; preds = %lpad16, %catch.disp ; CHECK: define internal i8* @"\01?test@@YAXXZ.catch"(i8*, i8*) ; CHECK: entry: -; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0) +; CHECK: [[RECOVER_J:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0) +; CHECK: [[J_PTR:\%.+]] = bitcast i8* [[RECOVER_J]] to i32* +; CHECK: [[RECOVER_I1:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1) +; CHECK: [[I_PTR1:\%.+]] = bitcast i8* [[RECOVER_I1]] to i32* +; CHECK: [[TMP3:\%.+]] = load i32, i32* [[J_PTR]], align 4 +; CHECK: store i32 [[TMP3]], i32* [[I_PTR1]] +; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ.catch.2", %invoke.cont2) +; CHECK: } + +; CHECK: define internal i8* @"\01?test@@YAXXZ.catch.1"(i8*, i8*) +; CHECK: entry: +; CHECK: [[RECOVER_F:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 2) +; CHECK: [[F_PTR:\%.+]] = bitcast i8* [[RECOVER_F]] to float* +; CHECK: [[TMP2:\%.+]] = load float, float* [[F_PTR]], align 4 +; CHECK: call void @"\01?handle_float@@YAXM@Z"(float [[TMP2]]) +; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont19) +; CHECK: } + +; CHECK: define internal i8* @"\01?test@@YAXXZ.catch.2"(i8*, i8*) +; CHECK: entry: +; CHECK: [[RECOVER_I:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1) ; CHECK: [[I_PTR:\%.+]] = bitcast i8* [[RECOVER_I]] to i32* ; CHECK: invoke void @"\01?may_throw@@YAXXZ"() ; CHECK: to label %invoke.cont2 unwind label %[[LPAD1_LABEL:lpad[0-9]*]] @@ -195,7 +215,7 @@ eh.resume: ; preds = %lpad16, %catch.disp ; CHECK: [[LPAD1_VAL:\%.+]] = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) ; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) ; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*) -; CHECK: [[RECOVER1:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 2, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.2", i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.1") +; CHECK: [[RECOVER1:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 0, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch", i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 2, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.1") ; CHECK: indirectbr i8* [[RECOVER1]], [label %invoke.cont2] ; ; CHECK: invoke.cont9: @@ -204,32 +224,11 @@ eh.resume: ; preds = %lpad16, %catch.disp ; CHECK: [[LPAD8_LABEL]]:{{[ ]+}}; preds = %invoke.cont2 ; CHECK: [[LPAD8_VAL:\%.+]] = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) ; CHECK: catch i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*) -; CHECK: [[RECOVER2:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 1, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.1") +; CHECK: [[RECOVER2:\%.+]] = call i8* (...) @llvm.eh.actions(i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0M@8" to i8*), i32 2, i8* (i8*, i8*)* @"\01?test@@YAXXZ.catch.1") ; CHECK: indirectbr i8* [[RECOVER2]], [] ; ; CHECK: } -; CHECK: define internal i8* @"\01?test@@YAXXZ.catch.1"(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_F:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 1) -; CHECK: [[F_PTR:\%.+]] = bitcast i8* [[RECOVER_F]] to float* -; CHECK: [[TMP2:\%.+]] = load float, float* [[F_PTR]], align 4 -; CHECK: call void @"\01?handle_float@@YAXM@Z"(float [[TMP2]]) -; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ", %try.cont19) -; CHECK: } - -; CHECK: define internal i8* @"\01?test@@YAXXZ.catch.2"(i8*, i8*) -; CHECK: entry: -; CHECK: [[RECOVER_J:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 2) -; CHECK: [[J_PTR:\%.+]] = bitcast i8* [[RECOVER_J]] to i32* -; CHECK: [[RECOVER_I1:\%.+]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @"\01?test@@YAXXZ" to i8*), i8* %1, i32 0) -; CHECK: [[I_PTR1:\%.+]] = bitcast i8* [[RECOVER_I1]] to i32* -; CHECK: [[TMP3:\%.+]] = load i32, i32* [[J_PTR]], align 4 -; CHECK: store i32 [[TMP3]], i32* [[I_PTR1]] -; CHECK: ret i8* blockaddress(@"\01?test@@YAXXZ.catch", %invoke.cont2) -; CHECK: } - - declare void @"\01?may_throw@@YAXXZ"() #1 declare i32 @__CxxFrameHandler3(...) diff --git a/llvm/test/CodeGen/WinEH/cppeh-nested-rethrow.ll b/llvm/test/CodeGen/WinEH/cppeh-nested-rethrow.ll index 1e8d63ec3fb7..60b404113345 100644 --- a/llvm/test/CodeGen/WinEH/cppeh-nested-rethrow.ll +++ b/llvm/test/CodeGen/WinEH/cppeh-nested-rethrow.ll @@ -180,28 +180,26 @@ unreachable: ; preds = %catch, %entry ; CHECK: } } -; The outlined test1.catch handler should not contain a return instruction. +; The outlined test1.catch handler should return to a valid block address. ; CHECK-LABEL: define internal i8* @"\01?test1@@YAXXZ.catch"(i8*, i8*) -; CHECK-NOT: ret +; CHECK-NOT: ret i8* inttoptr (i32 1 to i8*) ; CHECK: } -; The outlined test1.catch1 handler should return to a valid block address. +; The outlined test1.catch1 handler should not contain a return instruction. ; CHECK-LABEL: define internal i8* @"\01?test1@@YAXXZ.catch.1"(i8*, i8*) -; WILL-CHECK: ret i8* inttoptr ( -; CHECK-NOT: ret i8* inttoptr (i32 1 to i8*) -; CHECK: } - -; The outlined test2.catch handler should not contain a return instruction. -; CHECK-LABEL: define internal i8* @"\01?test2@@YAXXZ.catch"(i8*, i8*) ; CHECK-NOT: ret ; CHECK: } -; The outlined test2.catch1 handler should return to a valid block address. -; CHECK-LABEL: define internal i8* @"\01?test2@@YAXXZ.catch.2"(i8*, i8*) -; WILL-CHECK: ret i8* inttoptr ( +; The outlined test2.catch handler should return to a valid block address. +; CHECK-LABEL: define internal i8* @"\01?test2@@YAXXZ.catch"(i8*, i8*) ; CHECK-NOT: ret i8* inttoptr (i32 1 to i8*) ; CHECK: } +; The outlined test2.catch2 handler should not contain a return instruction. +; CHECK-LABEL: define internal i8* @"\01?test2@@YAXXZ.catch.2"(i8*, i8*) +; CHECK-NOT: ret +; CHECK: } + 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" } attributes #1 = { nounwind } diff --git a/llvm/test/CodeGen/WinEH/cppeh-similar-catch-blocks.ll b/llvm/test/CodeGen/WinEH/cppeh-similar-catch-blocks.ll index 92a8ff761158..81ee4542062d 100644 --- a/llvm/test/CodeGen/WinEH/cppeh-similar-catch-blocks.ll +++ b/llvm/test/CodeGen/WinEH/cppeh-similar-catch-blocks.ll @@ -86,7 +86,7 @@ $"\01??_C@_03PMGGPEJJ@?$CFd?6?$AA@" = comdat any ; This is just a minimal check to verify that main was handled by WinEHPrepare. ; CHECK: define i32 @main() ; CHECK: entry: -; CHECK: call void (...) @llvm.frameescape(i8* [[C_PTR:\%.+]], i32* [[X_PTR:\%.+]], i8* [[C2_PTR:\%.+]], i32* [[X2_PTR:\%.+]], i8* [[C3_PTR:\%.+]]) +; CHECK: call void (...) @llvm.frameescape(i32* [[X_PTR:\%.+]], i32* [[X2_PTR:\%.+]], i8* [[C2_PTR:\%.+]], i8* [[C3_PTR:\%.+]], i8* [[C_PTR:\%.+]]) ; CHECK: invoke void @_CxxThrowException ; CHECK: } diff --git a/llvm/test/CodeGen/WinEH/cppeh-state-calc-1.ll b/llvm/test/CodeGen/WinEH/cppeh-state-calc-1.ll index 87df6182aa87..3549b1d51dee 100644 --- a/llvm/test/CodeGen/WinEH/cppeh-state-calc-1.ll +++ b/llvm/test/CodeGen/WinEH/cppeh-state-calc-1.ll @@ -274,16 +274,16 @@ attributes #5 = { noreturn } ; CHECK-NEXT: .long .Lfunc_begin0@IMGREL ; CHECK-NEXT: .long -1 ; CHECK-NEXT: .long .Ltmp0@IMGREL -; CHECK-NEXT: .long 3 -; CHECK-NEXT: .long .Ltmp3@IMGREL ; CHECK-NEXT: .long 2 -; CHECK-NEXT: .long .Ltmp6@IMGREL +; CHECK-NEXT: .long .Ltmp3@IMGREL ; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp6@IMGREL +; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long .Lfunc_begin1@IMGREL -; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 3 ; CHECK-NEXT: .long .Lfunc_begin2@IMGREL -; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 4 ; CHECK-NEXT: .long .Lfunc_begin3@IMGREL -; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 5 ; CHECK-NEXT: .long .Lfunc_begin4@IMGREL -; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 6