Index: lib/CodeGen/WinEHPrepare.cpp =================================================================== --- lib/CodeGen/WinEHPrepare.cpp +++ lib/CodeGen/WinEHPrepare.cpp @@ -925,6 +925,26 @@ return CloningDirector::CloneInstruction; } + if (auto *Compare = dyn_cast(Inst)) { + // Look for compare instructions that use selector values that were not + // defined in the current block. A series of related catch dispatch blocks + // will share a loaded selector value, but after the first dispatch block + // we will have started outlining after the value is loaded. We can + // spot this case by looking at the compare operands. + for (auto &U : Compare->operands()) { + // Ignore any operands we've already mapped. + if (VMap.count(U.get())) + continue; + if (auto *Load = dyn_cast(U.get())) { + if (LPadMap.mapIfSelectorLoad(Load)) + VMap[Load] = ConstantInt::get(SelectorIDType, 1); + break; + } + } + // Whether we mapped a selector load above or not, the compare gets cloned. + return CloningDirector::CloneInstruction; + } + // 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 @@ -994,20 +1014,24 @@ if (ParentBB->isLandingPad() && !LPadMap.isOriginLandingPadBlock(ParentBB)) return CloningDirector::SkipInstruction; - // If an end catch occurs anywhere else the next instruction should be an - // unconditional branch instruction that we want to replace with a return - // to the the address of the branch target. - const BasicBlock *EndCatchBB = IntrinCall->getParent(); - const TerminatorInst *Terminator = EndCatchBB->getTerminator(); - const BranchInst *Branch = dyn_cast(Terminator); - assert(Branch && Branch->isUnconditional()); - assert(std::next(BasicBlock::const_iterator(IntrinCall)) == - BasicBlock::const_iterator(Branch)); - - BasicBlock *ContinueLabel = Branch->getSuccessor(0); - ReturnInst::Create(NewBB->getContext(), BlockAddress::get(ContinueLabel), - NewBB); - ReturnTargets.push_back(ContinueLabel); + // If an end catch occurs anywhere else we want to terminate the handler + // with a return to the code that follows the endcatch call. If the + // next instruction is not an unconditional branch, we need to split the + // block to provide a clear target for the return instruction. + BasicBlock *ContinueBB; + auto Next = std::next(BasicBlock::const_iterator(IntrinCall)); + const BranchInst *Branch = dyn_cast(Next); + if (!Branch || !Branch->isUnconditional()) { + // We're interrupting the cloning process at this location, so the + // const_cast we're doing here will not cause a problem. + ContinueBB = SplitBlock(const_cast(ParentBB), + const_cast(IntrinCall)); + } else { + ContinueBB = Branch->getSuccessor(0); + } + + ReturnInst::Create(NewBB->getContext(), BlockAddress::get(ContinueBB), NewBB); + ReturnTargets.push_back(ContinueBB); // We just added a terminator to the cloned block. // Tell the caller to stop processing the current basic block so that @@ -1461,12 +1485,19 @@ continue; if (Inst == Compare || Inst == Branch) continue; - if (!Inst->hasOneUse() || (Inst->user_back() != Compare)) - return createCleanupHandler(CleanupHandlerMap, BB); + // Loads of selector values may be used by multiple blocks, but if the + // loaded value is used in this block, it should be used by the + // compare instruction. + if (auto *Load = dyn_cast(Inst)) { + for (auto *U : Load->users()) { + if (cast(U)->getParent() == BB && U != Compare) + return createCleanupHandler(CleanupHandlerMap, BB); + } + continue; + } if (match(Inst, m_Intrinsic())) continue; - if (!isa(Inst)) - return createCleanupHandler(CleanupHandlerMap, BB); + return createCleanupHandler(CleanupHandlerMap, BB); } // The selector dispatch block should always terminate our search. assert(BB == EndBB);