From 5f50442d79df229027a8c5eda0d56f7a9cd55757 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Thu, 28 May 2015 22:00:24 +0000 Subject: [PATCH] [WinEH] Start inserting state number stores for C++ EH This moves all the state numbering code for C++ EH to WinEHPrepare so that we can call it from the X86 state numbering IR pass that runs before isel. Now we just call the same state numbering machinery and insert a bunch of stores. It also populates MachineModuleInfo with information about the current function. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@238514 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/CodeGen/WinEHFuncInfo.h | 7 + .../SelectionDAG/FunctionLoweringInfo.cpp | 374 +----------------- lib/CodeGen/WinEHPrepare.cpp | 374 ++++++++++++++++++ lib/Target/X86/X86WinEHState.cpp | 202 ++++++++-- test/CodeGen/X86/win32-eh-states.ll | 112 ++++++ test/CodeGen/X86/win32-eh.ll | 3 +- 6 files changed, 658 insertions(+), 414 deletions(-) create mode 100644 test/CodeGen/X86/win32-eh-states.ll diff --git a/include/llvm/CodeGen/WinEHFuncInfo.h b/include/llvm/CodeGen/WinEHFuncInfo.h index e2644edd4d1..1cff3203f2b 100644 --- a/include/llvm/CodeGen/WinEHFuncInfo.h +++ b/include/llvm/CodeGen/WinEHFuncInfo.h @@ -23,6 +23,7 @@ class BasicBlock; class Constant; class Function; class GlobalVariable; +class InvokeInst; class IntrinsicInst; class LandingPadInst; class MCSymbol; @@ -153,5 +154,11 @@ struct WinEHFuncInfo { NumIPToStateFuncsVisited(0) {} }; +/// Analyze the IR in ParentFn and it's handlers to build WinEHFuncInfo, which +/// describes the state numbers and tables used by __CxxFrameHandler3. This +/// analysis assumes that WinEHPrepare has already been run. +void calculateWinCXXEHStateNumbers(const Function *ParentFn, + WinEHFuncInfo &FuncInfo); + } #endif // LLVM_CODEGEN_WINEHFUNCINFO_H diff --git a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp index 7b5b8c4eabc..f3d75cb32a7 100644 --- a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -80,33 +80,6 @@ static ISD::NodeType getPreferredExtendForValue(const Value *V) { return ExtendKind; } -namespace { -struct WinEHNumbering { - WinEHNumbering(WinEHFuncInfo &FuncInfo) : FuncInfo(FuncInfo), - CurrentBaseState(-1), NextState(0) {} - - WinEHFuncInfo &FuncInfo; - int CurrentBaseState; - int NextState; - - SmallVector, 4> HandlerStack; - SmallPtrSet VisitedHandlers; - - int currentEHNumber() const { - return HandlerStack.empty() ? CurrentBaseState : HandlerStack.back()->getEHState(); - } - - void createUnwindMapEntry(int ToState, ActionHandler *AH); - void createTryBlockMapEntry(int TryLow, int TryHigh, - ArrayRef Handlers); - void processCallSite(MutableArrayRef> Actions, - ImmutableCallSite CS); - void popUnmatchedActions(int FirstMismatch); - void calculateStateNumbers(const Function &F); - void findActionRootLPads(const Function &F); -}; -} - void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf, SelectionDAG *DAG) { Fn = &fn; @@ -291,31 +264,18 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf, if (!isMSVCEHPersonality(Personality)) return; - WinEHFuncInfo *EHInfo = nullptr; if (Personality == EHPersonality::MSVC_Win64SEH) { addSEHHandlersForLPads(LPads); } else if (Personality == EHPersonality::MSVC_CXX) { const Function *WinEHParentFn = MMI.getWinEHParent(&fn); - 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. - // 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()); - } + WinEHFuncInfo &EHInfo = MMI.getWinEHFuncInfo(WinEHParentFn); + calculateWinCXXEHStateNumbers(WinEHParentFn, EHInfo); // Copy the state numbers to LandingPadInfo for the current function, which // could be a handler or the parent. for (const LandingPadInst *LP : LPads) { MachineBasicBlock *LPadMBB = MBBMap[LP->getParent()]; - MMI.addWinEHState(LPadMBB, EHInfo->LandingPadStateMap[LP]); + MMI.addWinEHState(LPadMBB, EHInfo.LandingPadStateMap[LP]); } } } @@ -358,334 +318,6 @@ void FunctionLoweringInfo::addSEHHandlersForLPads( } } -void WinEHNumbering::createUnwindMapEntry(int ToState, ActionHandler *AH) { - WinEHUnwindMapEntry UME; - UME.ToState = ToState; - if (auto *CH = dyn_cast_or_null(AH)) - UME.Cleanup = cast(CH->getHandlerBlockOrFunc()); - else - UME.Cleanup = nullptr; - FuncInfo.UnwindMap.push_back(UME); -} - -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() != (size_t)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; - assert(TBME.TryLow <= TBME.TryHigh); - for (CatchHandler *CH : Handlers) { - WinEHHandlerType HT; - if (CH->getSelector()->isNullValue()) { - HT.Adjectives = 0x40; - HT.TypeDescriptor = nullptr; - } else { - auto *GV = cast(CH->getSelector()->stripPointerCasts()); - // Selectors are always pointers to GlobalVariables with 'struct' type. - // The struct has two fields, adjectives and a type descriptor. - auto *CS = cast(GV->getInitializer()); - HT.Adjectives = - cast(CS->getAggregateElement(0U))->getZExtValue(); - HT.TypeDescriptor = - cast(CS->getAggregateElement(1)->stripPointerCasts()); - } - HT.Handler = cast(CH->getHandlerBlockOrFunc()); - HT.CatchObjRecoverIdx = CH->getExceptionVarIndex(); - TBME.HandlerArray.push_back(HT); - } - FuncInfo.TryBlockMap.push_back(TBME); -} - -static void print_name(const Value *V) { -#ifndef NDEBUG - if (!V) { - DEBUG(dbgs() << "null"); - return; - } - - if (const auto *F = dyn_cast(V)) - DEBUG(dbgs() << F->getName()); - else - DEBUG(V->dump()); -#endif -} - -void WinEHNumbering::processCallSite( - MutableArrayRef> Actions, - ImmutableCallSite CS) { - DEBUG(dbgs() << "processCallSite (EH state = " << currentEHNumber() - << ") for: "); - print_name(CS ? CS.getCalledValue() : nullptr); - DEBUG(dbgs() << '\n'); - - DEBUG(dbgs() << "HandlerStack: \n"); - for (int I = 0, E = HandlerStack.size(); I < E; ++I) { - DEBUG(dbgs() << " "); - print_name(HandlerStack[I]->getHandlerBlockOrFunc()); - DEBUG(dbgs() << '\n'); - } - DEBUG(dbgs() << "Actions: \n"); - for (int I = 0, E = Actions.size(); I < E; ++I) { - DEBUG(dbgs() << " "); - print_name(Actions[I]->getHandlerBlockOrFunc()); - DEBUG(dbgs() << '\n'); - } - int FirstMismatch = 0; - for (int E = std::min(HandlerStack.size(), Actions.size()); FirstMismatch < E; - ++FirstMismatch) { - if (HandlerStack[FirstMismatch]->getHandlerBlockOrFunc() != - Actions[FirstMismatch]->getHandlerBlockOrFunc()) - 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; - for (int I = HandlerStack.size() - 1; I >= FirstMismatch; --I) { - std::unique_ptr Handler = HandlerStack.pop_back_val(); - if (isa(Handler.get())) - PoppedCatches.push_back(cast(Handler.release())); - } - - int TryHigh = NextState - 1; - int LastTryLowIdx = 0; - for (int I = 0, E = PoppedCatches.size(); I != E; ++I) { - CatchHandler *CH = PoppedCatches[I]; - DEBUG(dbgs() << "Popped handler with state " << CH->getEHState() << "\n"); - if (I + 1 == E || CH->getEHState() != PoppedCatches[I + 1]->getEHState()) { - int TryLow = CH->getEHState(); - auto Handlers = - makeArrayRef(&PoppedCatches[LastTryLowIdx], I - LastTryLowIdx + 1); - DEBUG(dbgs() << "createTryBlockMapEntry(" << TryLow << ", " << TryHigh); - for (size_t J = 0; J < Handlers.size(); ++J) { - DEBUG(dbgs() << ", "); - print_name(Handlers[J]->getHandlerBlockOrFunc()); - } - DEBUG(dbgs() << ")\n"); - createTryBlockMapEntry(TryLow, TryHigh, Handlers); - LastTryLowIdx = I + 1; - } - } - - for (CatchHandler *CH : PoppedCatches) { - if (auto *F = dyn_cast(CH->getHandlerBlockOrFunc())) { - 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; - } -} - -void WinEHNumbering::calculateStateNumbers(const Function &F) { - auto I = VisitedHandlers.insert(&F); - if (!I.second) - return; // We've already visited this handler, don't renumber it. - - int OldBaseState = CurrentBaseState; - if (FuncInfo.HandlerBaseState.count(&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) { - for (const Instruction &I : BB) { - const auto *CI = dyn_cast(&I); - if (!CI || CI->doesNotThrow()) - continue; - processCallSite(None, CI); - } - 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; - processCallSite(ActionList, II); - ActionList.clear(); - FuncInfo.LandingPadStateMap[LPI] = currentEHNumber(); - DEBUG(dbgs() << "Assigning state " << currentEHNumber() - << " to landing pad at " << LPI->getParent()->getName() - << '\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/lib/CodeGen/WinEHPrepare.cpp b/lib/CodeGen/WinEHPrepare.cpp index 7246e1cf3ea..c2b3d84ca36 100644 --- a/lib/CodeGen/WinEHPrepare.cpp +++ b/lib/CodeGen/WinEHPrepare.cpp @@ -2480,3 +2480,377 @@ void llvm::parseEHActions( } std::reverse(Actions.begin(), Actions.end()); } + +namespace { +struct WinEHNumbering { + WinEHNumbering(WinEHFuncInfo &FuncInfo) : FuncInfo(FuncInfo), + CurrentBaseState(-1), NextState(0) {} + + WinEHFuncInfo &FuncInfo; + int CurrentBaseState; + int NextState; + + SmallVector, 4> HandlerStack; + SmallPtrSet VisitedHandlers; + + int currentEHNumber() const { + return HandlerStack.empty() ? CurrentBaseState : HandlerStack.back()->getEHState(); + } + + void createUnwindMapEntry(int ToState, ActionHandler *AH); + void createTryBlockMapEntry(int TryLow, int TryHigh, + ArrayRef Handlers); + void processCallSite(MutableArrayRef> Actions, + ImmutableCallSite CS); + void popUnmatchedActions(int FirstMismatch); + void calculateStateNumbers(const Function &F); + void findActionRootLPads(const Function &F); +}; +} + +void WinEHNumbering::createUnwindMapEntry(int ToState, ActionHandler *AH) { + WinEHUnwindMapEntry UME; + UME.ToState = ToState; + if (auto *CH = dyn_cast_or_null(AH)) + UME.Cleanup = cast(CH->getHandlerBlockOrFunc()); + else + UME.Cleanup = nullptr; + FuncInfo.UnwindMap.push_back(UME); +} + +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() != (size_t)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; + assert(TBME.TryLow <= TBME.TryHigh); + for (CatchHandler *CH : Handlers) { + WinEHHandlerType HT; + if (CH->getSelector()->isNullValue()) { + HT.Adjectives = 0x40; + HT.TypeDescriptor = nullptr; + } else { + auto *GV = cast(CH->getSelector()->stripPointerCasts()); + // Selectors are always pointers to GlobalVariables with 'struct' type. + // The struct has two fields, adjectives and a type descriptor. + auto *CS = cast(GV->getInitializer()); + HT.Adjectives = + cast(CS->getAggregateElement(0U))->getZExtValue(); + HT.TypeDescriptor = + cast(CS->getAggregateElement(1)->stripPointerCasts()); + } + HT.Handler = cast(CH->getHandlerBlockOrFunc()); + HT.CatchObjRecoverIdx = CH->getExceptionVarIndex(); + TBME.HandlerArray.push_back(HT); + } + FuncInfo.TryBlockMap.push_back(TBME); +} + +static void print_name(const Value *V) { +#ifndef NDEBUG + if (!V) { + DEBUG(dbgs() << "null"); + return; + } + + if (const auto *F = dyn_cast(V)) + DEBUG(dbgs() << F->getName()); + else + DEBUG(V->dump()); +#endif +} + +void WinEHNumbering::processCallSite( + MutableArrayRef> Actions, + ImmutableCallSite CS) { + DEBUG(dbgs() << "processCallSite (EH state = " << currentEHNumber() + << ") for: "); + print_name(CS ? CS.getCalledValue() : nullptr); + DEBUG(dbgs() << '\n'); + + DEBUG(dbgs() << "HandlerStack: \n"); + for (int I = 0, E = HandlerStack.size(); I < E; ++I) { + DEBUG(dbgs() << " "); + print_name(HandlerStack[I]->getHandlerBlockOrFunc()); + DEBUG(dbgs() << '\n'); + } + DEBUG(dbgs() << "Actions: \n"); + for (int I = 0, E = Actions.size(); I < E; ++I) { + DEBUG(dbgs() << " "); + print_name(Actions[I]->getHandlerBlockOrFunc()); + DEBUG(dbgs() << '\n'); + } + int FirstMismatch = 0; + for (int E = std::min(HandlerStack.size(), Actions.size()); FirstMismatch < E; + ++FirstMismatch) { + if (HandlerStack[FirstMismatch]->getHandlerBlockOrFunc() != + Actions[FirstMismatch]->getHandlerBlockOrFunc()) + 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; + for (int I = HandlerStack.size() - 1; I >= FirstMismatch; --I) { + std::unique_ptr Handler = HandlerStack.pop_back_val(); + if (isa(Handler.get())) + PoppedCatches.push_back(cast(Handler.release())); + } + + int TryHigh = NextState - 1; + int LastTryLowIdx = 0; + for (int I = 0, E = PoppedCatches.size(); I != E; ++I) { + CatchHandler *CH = PoppedCatches[I]; + DEBUG(dbgs() << "Popped handler with state " << CH->getEHState() << "\n"); + if (I + 1 == E || CH->getEHState() != PoppedCatches[I + 1]->getEHState()) { + int TryLow = CH->getEHState(); + auto Handlers = + makeArrayRef(&PoppedCatches[LastTryLowIdx], I - LastTryLowIdx + 1); + DEBUG(dbgs() << "createTryBlockMapEntry(" << TryLow << ", " << TryHigh); + for (size_t J = 0; J < Handlers.size(); ++J) { + DEBUG(dbgs() << ", "); + print_name(Handlers[J]->getHandlerBlockOrFunc()); + } + DEBUG(dbgs() << ")\n"); + createTryBlockMapEntry(TryLow, TryHigh, Handlers); + LastTryLowIdx = I + 1; + } + } + + for (CatchHandler *CH : PoppedCatches) { + if (auto *F = dyn_cast(CH->getHandlerBlockOrFunc())) { + 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; + } +} + +void WinEHNumbering::calculateStateNumbers(const Function &F) { + auto I = VisitedHandlers.insert(&F); + if (!I.second) + return; // We've already visited this handler, don't renumber it. + + int OldBaseState = CurrentBaseState; + if (FuncInfo.HandlerBaseState.count(&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) { + for (const Instruction &I : BB) { + const auto *CI = dyn_cast(&I); + if (!CI || CI->doesNotThrow()) + continue; + processCallSite(None, CI); + } + 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; + processCallSite(ActionList, II); + ActionList.clear(); + FuncInfo.LandingPadStateMap[LPI] = currentEHNumber(); + DEBUG(dbgs() << "Assigning state " << currentEHNumber() + << " to landing pad at " << LPI->getParent()->getName() + << '\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(); + } +} + +void llvm::calculateWinCXXEHStateNumbers(const Function *ParentFn, + WinEHFuncInfo &FuncInfo) { + // Return if it's already been done. + if (!FuncInfo.LandingPadStateMap.empty()) + return; + + WinEHNumbering Num(FuncInfo); + Num.findActionRootLPads(*ParentFn); + // The VisitedHandlers list is used by both findActionRootLPads and + // calculateStateNumbers, but both functions need to visit all handlers. + Num.VisitedHandlers.clear(); + Num.calculateStateNumbers(*ParentFn); + // Pop everything on the handler stack. + // 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()); +} diff --git a/lib/Target/X86/X86WinEHState.cpp b/lib/Target/X86/X86WinEHState.cpp index 4efaada4092..1a205e8aec4 100644 --- a/lib/Target/X86/X86WinEHState.cpp +++ b/lib/Target/X86/X86WinEHState.cpp @@ -16,6 +16,7 @@ #include "X86.h" #include "llvm/Analysis/LibCallSemantics.h" +#include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/WinEHFuncInfo.h" #include "llvm/IR/Dominators.h" @@ -59,14 +60,19 @@ public: private: void emitExceptionRegistrationRecord(Function *F); - void linkExceptionRegistration(IRBuilder<> &Builder, Value *RegNode, - Value *Handler); - void unlinkExceptionRegistration(IRBuilder<> &Builder, Value *RegNode); + void linkExceptionRegistration(IRBuilder<> &Builder, Value *Handler); + void unlinkExceptionRegistration(IRBuilder<> &Builder); + void addCXXStateStores(Function &F, MachineModuleInfo &MMI); + void addCXXStateStoresToFunclet(Value *ParentRegNode, WinEHFuncInfo &FuncInfo, + Function &F, int BaseState); + void insertStateNumberStore(Value *ParentRegNode, Instruction *IP, int State); Value *emitEHLSDA(IRBuilder<> &Builder, Function *F); Function *generateLSDAInEAXThunk(Function *ParentFunc); + int escapeRegNode(Function &F); + // Module-level type getters. Type *getEHRegistrationType(); Type *getSEH3RegistrationType(); @@ -83,6 +89,19 @@ private: // Per-function state EHPersonality Personality = EHPersonality::Unknown; Function *PersonalityFn = nullptr; + + /// The stack allocation containing all EH data, including the link in the + /// fs:00 chain and the current state. + AllocaInst *RegNode = nullptr; + + /// Struct type of RegNode. Used for GEPing. + Type *RegNodeTy = nullptr; + + /// The index of the state field of RegNode. + int StateFieldIndex = ~0U; + + /// The linked list node subobject inside of RegNode. + Value *Link = nullptr; }; } @@ -137,7 +156,13 @@ bool WinEHStatePass::runOnFunction(Function &F) { return false; emitExceptionRegistrationRecord(&F); - // FIXME: State insertion. + + auto *MMIPtr = getAnalysisIfAvailable(); + assert(MMIPtr && "MachineModuleInfo should always be available"); + MachineModuleInfo &MMI = *MMIPtr; + if (Personality == EHPersonality::MSVC_CXX) { + addCXXStateStores(F, MMI); + } // Reset per-function state. PersonalityFn = nullptr; @@ -238,62 +263,61 @@ void WinEHStatePass::emitExceptionRegistrationRecord(Function *F) { StringRef PersonalityName = PersonalityFn->getName(); IRBuilder<> Builder(&F->getEntryBlock(), F->getEntryBlock().begin()); Type *Int8PtrType = Builder.getInt8PtrTy(); - Value *SubRecord = nullptr; if (PersonalityName == "__CxxFrameHandler3") { - Type *RegNodeTy = getCXXEH3RegistrationType(); - Value *RegNode = Builder.CreateAlloca(RegNodeTy); + RegNodeTy = getCXXEH3RegistrationType(); + RegNode = Builder.CreateAlloca(RegNodeTy); // FIXME: We can skip this in -GS- mode, when we figure that out. // SavedESP = llvm.stacksave() Value *SP = Builder.CreateCall( Intrinsic::getDeclaration(TheModule, Intrinsic::stacksave), {}); Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0)); // TryLevel = -1 - Builder.CreateStore(Builder.getInt32(-1), - Builder.CreateStructGEP(RegNodeTy, RegNode, 2)); + StateFieldIndex = 2; + insertStateNumberStore(RegNode, Builder.GetInsertPoint(), -1); // Handler = __ehhandler$F Function *Trampoline = generateLSDAInEAXThunk(F); - SubRecord = Builder.CreateStructGEP(RegNodeTy, RegNode, 1); - linkExceptionRegistration(Builder, SubRecord, Trampoline); + Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 1); + linkExceptionRegistration(Builder, Trampoline); } else if (PersonalityName == "_except_handler3") { - Type *RegNodeTy = getSEH3RegistrationType(); - Value *RegNode = Builder.CreateAlloca(RegNodeTy); + RegNodeTy = getSEH3RegistrationType(); + RegNode = Builder.CreateAlloca(RegNodeTy); // TryLevel = -1 - Builder.CreateStore(Builder.getInt32(-1), - Builder.CreateStructGEP(RegNodeTy, RegNode, 2)); + StateFieldIndex = 2; + insertStateNumberStore(RegNode, Builder.GetInsertPoint(), -1); // ScopeTable = llvm.x86.seh.lsda(F) Value *LSDA = emitEHLSDA(Builder, F); Builder.CreateStore(LSDA, Builder.CreateStructGEP(RegNodeTy, RegNode, 1)); - SubRecord = Builder.CreateStructGEP(RegNodeTy, RegNode, 0); - linkExceptionRegistration(Builder, SubRecord, PersonalityFn); + Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 0); + linkExceptionRegistration(Builder, PersonalityFn); } else if (PersonalityName == "_except_handler4") { - Type *RegNodeTy = getSEH4RegistrationType(); - Value *RegNode = Builder.CreateAlloca(RegNodeTy); + RegNodeTy = getSEH4RegistrationType(); + RegNode = Builder.CreateAlloca(RegNodeTy); // SavedESP = llvm.stacksave() Value *SP = Builder.CreateCall( Intrinsic::getDeclaration(TheModule, Intrinsic::stacksave), {}); Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0)); - // TryLevel = -2 - Builder.CreateStore(Builder.getInt32(-2), - Builder.CreateStructGEP(RegNodeTy, RegNode, 4)); + // TryLevel = -1 + StateFieldIndex = 4; + insertStateNumberStore(RegNode, Builder.GetInsertPoint(), -1); // FIXME: XOR the LSDA with __security_cookie. // ScopeTable = llvm.x86.seh.lsda(F) Value *FI8 = Builder.CreateBitCast(F, Int8PtrType); Value *LSDA = Builder.CreateCall( Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_lsda), FI8); Builder.CreateStore(LSDA, Builder.CreateStructGEP(RegNodeTy, RegNode, 1)); - SubRecord = Builder.CreateStructGEP(RegNodeTy, RegNode, 2); - linkExceptionRegistration(Builder, SubRecord, PersonalityFn); + Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 2); + linkExceptionRegistration(Builder, PersonalityFn); } else { llvm_unreachable("unexpected personality function"); } - // FIXME: Insert an unlink before all returns. + // Insert an unlink before all returns. for (BasicBlock &BB : *F) { TerminatorInst *T = BB.getTerminator(); if (!isa(T)) continue; Builder.SetInsertPoint(T); - unlinkExceptionRegistration(Builder, SubRecord); + unlinkExceptionRegistration(Builder); } } @@ -342,33 +366,127 @@ Function *WinEHStatePass::generateLSDAInEAXThunk(Function *ParentFunc) { } void WinEHStatePass::linkExceptionRegistration(IRBuilder<> &Builder, - Value *RegNode, Value *Handler) { - Type *RegNodeTy = getEHRegistrationType(); + Value *Handler) { + Type *LinkTy = getEHRegistrationType(); // Handler = Handler Handler = Builder.CreateBitCast(Handler, Builder.getInt8PtrTy()); - Builder.CreateStore(Handler, Builder.CreateStructGEP(RegNodeTy, RegNode, 1)); + Builder.CreateStore(Handler, Builder.CreateStructGEP(LinkTy, Link, 1)); // Next = [fs:00] Constant *FSZero = - Constant::getNullValue(RegNodeTy->getPointerTo()->getPointerTo(257)); + Constant::getNullValue(LinkTy->getPointerTo()->getPointerTo(257)); Value *Next = Builder.CreateLoad(FSZero); - Builder.CreateStore(Next, Builder.CreateStructGEP(RegNodeTy, RegNode, 0)); - // [fs:00] = RegNode - Builder.CreateStore(RegNode, FSZero); + Builder.CreateStore(Next, Builder.CreateStructGEP(LinkTy, Link, 0)); + // [fs:00] = Link + Builder.CreateStore(Link, FSZero); } -void WinEHStatePass::unlinkExceptionRegistration(IRBuilder<> &Builder, - Value *RegNode) { - // Clone RegNode into the current BB for better address mode folding. - if (auto *GEP = dyn_cast(RegNode)) { +void WinEHStatePass::unlinkExceptionRegistration(IRBuilder<> &Builder) { + // Clone Link into the current BB for better address mode folding. + if (auto *GEP = dyn_cast(Link)) { GEP = cast(GEP->clone()); Builder.Insert(GEP); - RegNode = GEP; + Link = GEP; } - Type *RegNodeTy = getEHRegistrationType(); - // [fs:00] = RegNode->Next + Type *LinkTy = getEHRegistrationType(); + // [fs:00] = Link->Next Value *Next = - Builder.CreateLoad(Builder.CreateStructGEP(RegNodeTy, RegNode, 0)); + Builder.CreateLoad(Builder.CreateStructGEP(LinkTy, Link, 0)); Constant *FSZero = - Constant::getNullValue(RegNodeTy->getPointerTo()->getPointerTo(257)); + Constant::getNullValue(LinkTy->getPointerTo()->getPointerTo(257)); Builder.CreateStore(Next, FSZero); } + +void WinEHStatePass::addCXXStateStores(Function &F, MachineModuleInfo &MMI) { + WinEHFuncInfo &FuncInfo = MMI.getWinEHFuncInfo(&F); + calculateWinCXXEHStateNumbers(&F, FuncInfo); + + // The base state for the parent is -1. + addCXXStateStoresToFunclet(RegNode, FuncInfo, F, -1); + + // Set up RegNodeEscapeIndex + int RegNodeEscapeIndex = escapeRegNode(F); + + // Only insert stores in catch handlers. + Function *FrameRecover = + Intrinsic::getDeclaration(TheModule, Intrinsic::framerecover); + Function *FrameAddress = + Intrinsic::getDeclaration(TheModule, Intrinsic::frameaddress); + Constant *FI8 = + ConstantExpr::getBitCast(&F, Type::getInt8PtrTy(TheModule->getContext())); + for (auto P : FuncInfo.HandlerBaseState) { + Function *Handler = const_cast(P.first); + int BaseState = P.second; + IRBuilder<> Builder(&Handler->getEntryBlock(), + Handler->getEntryBlock().begin()); + // FIXME: Find and reuse such a call if present. + Value *ParentFP = Builder.CreateCall(FrameAddress, {Builder.getInt32(1)}); + Value *RecoveredRegNode = Builder.CreateCall( + FrameRecover, {FI8, ParentFP, Builder.getInt32(RegNodeEscapeIndex)}); + RecoveredRegNode = + Builder.CreateBitCast(RecoveredRegNode, RegNodeTy->getPointerTo(0)); + addCXXStateStoresToFunclet(RecoveredRegNode, FuncInfo, *Handler, BaseState); + } +} + +/// Escape RegNode so that we can access it from child handlers. Find the call +/// to frameescape, if any, in the entry block and append RegNode to the list +/// of arguments. +int WinEHStatePass::escapeRegNode(Function &F) { + // Find the call to frameescape and extract its arguments. + IntrinsicInst *EscapeCall = nullptr; + for (Instruction &I : F.getEntryBlock()) { + IntrinsicInst *II = dyn_cast(&I); + if (II && II->getIntrinsicID() == Intrinsic::frameescape) { + EscapeCall = II; + break; + } + } + SmallVector Args; + if (EscapeCall) { + auto Ops = EscapeCall->arg_operands(); + Args.append(Ops.begin(), Ops.end()); + } + Args.push_back(RegNode); + + // Replace the call (if it exists) with new one. Otherwise, insert at the end + // of the entry block. + IRBuilder<> Builder(&F.getEntryBlock(), + EscapeCall ? EscapeCall : F.getEntryBlock().end()); + Builder.CreateCall( + Intrinsic::getDeclaration(TheModule, Intrinsic::frameescape), Args); + if (EscapeCall) + EscapeCall->eraseFromParent(); + return Args.size() - 1; +} + +void WinEHStatePass::addCXXStateStoresToFunclet(Value *ParentRegNode, + WinEHFuncInfo &FuncInfo, + Function &F, int BaseState) { + // Iterate all the instructions and emit state number stores. + for (BasicBlock &BB : F) { + for (Instruction &I : BB) { + if (auto *CI = dyn_cast(&I)) { + // Possibly throwing call instructions have no actions to take after + // an unwind. Ensure they are in the -1 state. + if (CI->doesNotThrow()) + continue; + insertStateNumberStore(ParentRegNode, CI, BaseState); + } else if (auto *II = dyn_cast(&I)) { + // Look up the state number of the landingpad this unwinds to. + LandingPadInst *LPI = II->getUnwindDest()->getLandingPadInst(); + // FIXME: Why does this assertion fail? + //assert(FuncInfo.LandingPadStateMap.count(LPI) && "LP has no state!"); + int State = FuncInfo.LandingPadStateMap[LPI]; + insertStateNumberStore(ParentRegNode, II, State); + } + } + } +} + +void WinEHStatePass::insertStateNumberStore(Value *ParentRegNode, + Instruction *IP, int State) { + IRBuilder<> Builder(IP); + Value *StateField = + Builder.CreateStructGEP(RegNodeTy, ParentRegNode, StateFieldIndex); + Builder.CreateStore(Builder.getInt32(State), StateField); +} diff --git a/test/CodeGen/X86/win32-eh-states.ll b/test/CodeGen/X86/win32-eh-states.ll new file mode 100644 index 00000000000..6d561280367 --- /dev/null +++ b/test/CodeGen/X86/win32-eh-states.ll @@ -0,0 +1,112 @@ +; RUN: llc -mtriple=i686-pc-windows-msvc < %s | FileCheck %s + +; Based on this source: +; extern "C" void may_throw(int); +; void f() { +; try { +; may_throw(1); +; try { +; may_throw(2); +; } catch (int) { +; may_throw(3); +; } +; } catch (int) { +; may_throw(4); +; } +; } + +%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] } +%eh.CatchHandlerType = type { i32, i8* } + +declare void @may_throw(i32) +declare i32 @__CxxFrameHandler3(...) +declare void @llvm.eh.begincatch(i8*, i8*) +declare void @llvm.eh.endcatch() +declare i32 @llvm.eh.typeid.for(i8*) + +$"\01??_R0H@8" = comdat any + +@"\01??_7type_info@@6B@" = external constant i8* +@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat +@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" + +define void @f() #0 { +entry: + invoke void @may_throw(i32 1) + to label %invoke.cont unwind label %lpad + +invoke.cont: ; preds = %entry + invoke void @may_throw(i32 2) + to label %try.cont.9 unwind label %lpad.1 + +try.cont.9: ; preds = %invoke.cont.3, %invoke.cont, %catch.7 + ; FIXME: Something about our CFG breaks TailDuplication. This empy asm blocks + ; it so we can focus on testing the state numbering. + call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"() + ret void + +lpad: ; preds = %catch, %entry + %0 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) + catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.0 + %1 = extractvalue { i8*, i32 } %0, 0 + %2 = extractvalue { i8*, i32 } %0, 1 + br label %catch.dispatch.4 + +lpad.1: ; preds = %invoke.cont + %3 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) + catch i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*) + %4 = extractvalue { i8*, i32 } %3, 0 + %5 = extractvalue { i8*, i32 } %3, 1 + %6 = tail call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*)) #3 + %matches = icmp eq i32 %5, %6 + br i1 %matches, label %catch, label %catch.dispatch.4 + +catch.dispatch.4: ; preds = %lpad.1, %lpad + %exn.slot.0 = phi i8* [ %4, %lpad.1 ], [ %1, %lpad ] + %ehselector.slot.0 = phi i32 [ %5, %lpad.1 ], [ %2, %lpad ] + %.pre = tail call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*)) #3 + %matches6 = icmp eq i32 %ehselector.slot.0, %.pre + br i1 %matches6, label %catch.7, label %eh.resume + +catch.7: ; preds = %catch.dispatch.4 + tail call void @llvm.eh.begincatch(i8* %exn.slot.0, i8* null) #3 + tail call void @may_throw(i32 4) + tail call void @llvm.eh.endcatch() #3 + br label %try.cont.9 + +catch: ; preds = %lpad.1 + tail call void @llvm.eh.begincatch(i8* %4, i8* null) #3 + invoke void @may_throw(i32 3) + to label %invoke.cont.3 unwind label %lpad + +invoke.cont.3: ; preds = %catch + tail call void @llvm.eh.endcatch() #3 + br label %try.cont.9 + +eh.resume: ; preds = %catch.dispatch.4 + %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn.slot.0, 0 + %lpad.val.12 = insertvalue { i8*, i32 } %lpad.val, i32 %ehselector.slot.0, 1 + resume { i8*, i32 } %lpad.val.12 +} + +; CHECK-LABEL: _f: +; CHECK: movl $-1, [[state:[0-9]+]](%esp) +; CHECK: movl $___ehhandler$f, {{.*}} +; +; CHECK: movl $0, [[state]](%esp) +; CHECK: movl $1, (%esp) +; CHECK: calll _may_throw +; +; CHECK: movl $1, [[state]](%esp) +; CHECK: movl $2, (%esp) +; CHECK: calll _may_throw + +; CHECK-LABEL: _f.catch: +; CHECK: movl $4, Lf$frame_escape_{{[0-9]+.*}} +; CHECK: movl $4, (%esp) +; CHECK: calll _may_throw + +; CHECK-LABEL: _f.catch.1: +; CHECK: movl $3, Lf$frame_escape_{{[0-9]+.*}} +; CHECK: movl $3, (%esp) +; CHECK: calll _may_throw diff --git a/test/CodeGen/X86/win32-eh.ll b/test/CodeGen/X86/win32-eh.ll index 4d3c34ed6c1..f18cd665ea7 100644 --- a/test/CodeGen/X86/win32-eh.ll +++ b/test/CodeGen/X86/win32-eh.ll @@ -46,7 +46,7 @@ catchall: ; CHECK-LABEL: _use_except_handler4: ; CHECK: subl ${{[0-9]+}}, %esp ; CHECK: movl %esp, (%esp) -; CHECK: movl $-2, 20(%esp) +; CHECK: movl $-1, 20(%esp) ; CHECK: movl $L__ehtable$use_except_handler4, 4(%esp) ; CHECK: leal 8(%esp), %[[node:[^ ,]*]] ; CHECK: movl $__except_handler4, 12(%esp) @@ -81,6 +81,7 @@ catchall: ; CHECK: movl %fs:0, %[[next:[^ ,]*]] ; CHECK: movl %[[next]], 4(%esp) ; CHECK: movl %[[node]], %fs:0 +; CHECK: movl $0, 12(%esp) ; CHECK: calll _may_throw_or_crash ; CHECK: movl 4(%esp), %[[next:[^ ,]*]] ; CHECK: movl %[[next]], %fs:0