Index: include/llvm/CodeGen/WinEHFuncInfo.h =================================================================== --- include/llvm/CodeGen/WinEHFuncInfo.h +++ include/llvm/CodeGen/WinEHFuncInfo.h @@ -136,6 +136,7 @@ DenseMap CatchHandlerParentFrameObjIdx; DenseMap CatchHandlerParentFrameObjOffset; DenseMap CatchHandlerMaxState; + DenseMap HandlerBaseState; SmallVector UnwindMap; SmallVector TryBlockMap; SmallVector, 4> IPToStateList; Index: lib/CodeGen/AsmPrinter/Win64Exception.cpp =================================================================== --- lib/CodeGen/AsmPrinter/Win64Exception.cpp +++ lib/CodeGen/AsmPrinter/Win64Exception.cpp @@ -299,6 +299,17 @@ // The parent function and the catch handlers contribute to the 'ip2state' // table. + + // Include ip2state entries for the beginning of the main function and + // for catch handler functions. + if (F == ParentF) { + FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1)); + LastEHState = -1; + } else if (FuncInfo.HandlerBaseState.count(F)) { + FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, + FuncInfo.HandlerBaseState[F])); + LastEHState = FuncInfo.HandlerBaseState[F]; + } for (const auto &MBB : *MF) { for (const auto &MI : MBB) { if (!MI.isEHLabel()) { @@ -323,7 +334,8 @@ assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] && "Inconsistent landing pad map!"); - if (SawPotentiallyThrowing) { + // FIXME: Should this be using FuncInfo.HandlerBaseState? + if (SawPotentiallyThrowing && LastEHState != -1) { FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1)); SawPotentiallyThrowing = false; LastEHState = -1; Index: lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp =================================================================== --- lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -82,16 +82,18 @@ namespace { struct WinEHNumbering { - WinEHNumbering(WinEHFuncInfo &FuncInfo) : FuncInfo(FuncInfo), NextState(0) {} + WinEHNumbering(WinEHFuncInfo &FuncInfo) : FuncInfo(FuncInfo), + CurrentBaseState(-1), NextState(0) {} WinEHFuncInfo &FuncInfo; + int CurrentBaseState; int NextState; SmallVector HandlerStack; SmallPtrSet VisitedHandlers; int currentEHNumber() const { - return HandlerStack.empty() ? -1 : HandlerStack.back()->getEHState(); + return HandlerStack.empty() ? CurrentBaseState : HandlerStack.back()->getEHState(); } void createUnwindMapEntry(int ToState, ActionHandler *AH); @@ -401,12 +403,30 @@ void WinEHNumbering::processCallSite(ArrayRef 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; + // Delete any actions that are already represented on the handler stack. delete Actions[FirstMismatch]; } @@ -429,42 +449,74 @@ // will not push any more actions. int TryHigh = NextState - 1; if (!EnteringScope && !PoppedCatches.empty()) { + DEBUG(dbgs() << "createUnwindMapEntry(" << currentEHNumber() << ", " << TryHigh << '\n'); createUnwindMapEntry(currentEHNumber(), nullptr); - ++NextState; } 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 (int 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 (auto *F = dyn_cast(CH->getHandlerBlockOrFunc())) { + DEBUG(dbgs() << "Assigning base state " << NextState << " to "); + print_name(F); + DEBUG(dbgs() << '\n'); + FuncInfo.HandlerBaseState[F] = NextState; + ++NextState; calculateStateNumbers(*F); + } 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() > FirstMismatch) { + for (int E = std::min(HandlerStack.size(), Actions.size()); FirstMismatch < E; + ++FirstMismatch) { + if (HandlerStack[FirstMismatch]->getHandlerBlockOrFunc() != + Actions[FirstMismatch]->getHandlerBlockOrFunc()) + break; + delete Actions[FirstMismatch]; + } + } + + 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]); // 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]); + DEBUG(dbgs() << "setEHState for handler to " << NextState << "\n"); Actions[I]->setEHState(NextState); NextState++; - DEBUG(dbgs() << "Creating unwind map entry for: ("); - print_name(Actions[I]->getHandlerBlockOrFunc()); - DEBUG(dbgs() << ", " << currentEHNumber() << ")\n"); } HandlerStack.push_back(Actions[I]); LastActionWasCatch = CurrActionIsCatch; @@ -480,6 +532,11 @@ 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]; + } + DEBUG(dbgs() << "Calculating state numbers for: " << F.getName() << '\n'); SmallVector ActionList; for (const BasicBlock &BB : F) { @@ -498,12 +555,19 @@ 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'); } FuncInfo.CatchHandlerMaxState[&F] = NextState - 1; + + CurrentBaseState = OldBaseState; } /// clear - Clear out all the function-specific state. This returns this Index: test/CodeGen/WinEH/cppeh-prepared-catch-reordered.ll =================================================================== --- test/CodeGen/WinEH/cppeh-prepared-catch-reordered.ll +++ test/CodeGen/WinEH/cppeh-prepared-catch-reordered.ll @@ -120,7 +120,7 @@ ; CHECK-NEXT: .long ($stateUnwindMap$main)@IMGREL ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long ($tryMap$main)@IMGREL -; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 3 ; CHECK-NEXT: .long ($ip2state$main)@IMGREL ; CHECK-NEXT: .long 40 ; CHECK-NEXT: .long 0 Index: test/CodeGen/WinEH/cppeh-prepared-catch.ll =================================================================== --- test/CodeGen/WinEH/cppeh-prepared-catch.ll +++ test/CodeGen/WinEH/cppeh-prepared-catch.ll @@ -127,7 +127,7 @@ ; CHECK-NEXT: .long ("$stateUnwindMap$?f@@YAXXZ")@IMGREL ; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long ("$tryMap$?f@@YAXXZ")@IMGREL -; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 6 ; CHECK-NEXT: .long ("$ip2state$?f@@YAXXZ")@IMGREL ; CHECK-NEXT: .long 32 ; CHECK-NEXT: .long 0 @@ -165,8 +165,14 @@ ; CHECK-NEXT: .long "?f@@YAXXZ.catch1"@IMGREL ; CHECK-NEXT: .long ".L?f@@YAXXZ.catch1$parent_frame_offset" ; CHECK-NEXT:"$ip2state$?f@@YAXXZ": +; CHECK-NEXT: .long .Lfunc_begin0@IMGREL +; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long .Ltmp0@IMGREL ; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long .Lfunc_begin1@IMGREL +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long .Lfunc_begin2@IMGREL +; CHECK-NEXT: .long -1 ; CHECK-NEXT: .long .Ltmp13@IMGREL ; CHECK-NEXT: .long 1 ; CHECK-NEXT: .long .Ltmp16@IMGREL Index: test/CodeGen/WinEH/cppeh-prepared-cleanups.ll =================================================================== --- test/CodeGen/WinEH/cppeh-prepared-cleanups.ll +++ test/CodeGen/WinEH/cppeh-prepared-cleanups.ll @@ -36,7 +36,7 @@ ; CHECK-NEXT: .long ("$stateUnwindMap$?test1@@YAXXZ")@IMGREL ; CHECK-NEXT: .long 0 ; CHECK-NEXT: .long 0 -; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 2 ; CHECK-NEXT: .long ("$ip2state$?test1@@YAXXZ")@IMGREL ; CHECK-NEXT: .long 32 ; CHECK-NEXT: .long 0 @@ -45,6 +45,8 @@ ; CHECK-NEXT: .long -1 ; CHECK-NEXT: .long "?test1@@YAXXZ.cleanup"@IMGREL ; CHECK-NEXT:"$ip2state$?test1@@YAXXZ": +; CHECK-NEXT: .long .Lfunc_begin0@IMGREL +; CHECK-NEXT: .long -1 ; CHECK-NEXT: .long .Ltmp0@IMGREL ; CHECK-NEXT: .long 0