-
- // See if the clause we're looking for is a catch-all.
- // If so, the catch begins immediately.
- Constant *ExpectedSelector =
- LPad->getClause(HandlersFound)->stripPointerCasts();
- if (isa<ConstantPointerNull>(ExpectedSelector)) {
- // The catch all must occur last.
- assert(HandlersFound == NumClauses - 1);
-
- // There can be additional selector dispatches in the call chain that we
- // need to ignore.
- BasicBlock *CatchBlock = nullptr;
- Constant *Selector;
- while (BB && isSelectorDispatch(BB, CatchBlock, Selector, NextBB)) {
- DEBUG(dbgs() << " Found extra catch dispatch in block "
- << CatchBlock->getName() << "\n");
- BB = NextBB;
- }
-
- // Add the catch handler to the action list.
- CatchHandler *Action = nullptr;
- if (CatchHandlerMap.count(BB) && CatchHandlerMap[BB] != nullptr) {
- // If the CatchHandlerMap already has an entry for this BB, re-use it.
- Action = CatchHandlerMap[BB];
- assert(Action->getSelector() == ExpectedSelector);
- } else {
- // We don't expect a selector dispatch, but there may be a call to
- // llvm.eh.begincatch, which separates catch handling code from
- // cleanup code in the same control flow. This call looks for the
- // begincatch intrinsic.
- Action = findCatchHandler(BB, NextBB, VisitedBlocks);
- if (Action) {
- // For C++ EH, check if there is any interesting cleanup code before
- // we begin the catch. This is important because cleanups cannot
- // rethrow exceptions but code called from catches can. For SEH, it
- // isn't important if some finally code before a catch-all is executed
- // out of line or after recovering from the exception.
- if (Personality == EHPersonality::MSVC_CXX)
- findCleanupHandlers(Actions, BB, BB);
- } else {
- // If an action was not found, it means that the control flows
- // directly into the catch-all handler and there is no cleanup code.
- // That's an expected situation and we must create a catch action.
- // Since this is a catch-all handler, the selector won't actually
- // appear in the code anywhere. ExpectedSelector here is the constant
- // null ptr that we got from the landing pad instruction.
- Action = new CatchHandler(BB, ExpectedSelector, nullptr);
- CatchHandlerMap[BB] = Action;
- }
- }
- Actions.insertCatchHandler(Action);
- DEBUG(dbgs() << " Catch all handler at block " << BB->getName() << "\n");
- ++HandlersFound;
-
- // Once we reach a catch-all, don't expect to hit a resume instruction.
- BB = nullptr;
- break;
- }
-
- CatchHandler *CatchAction = findCatchHandler(BB, NextBB, VisitedBlocks);
- assert(CatchAction);
-
- // See if there is any interesting code executed before the dispatch.
- findCleanupHandlers(Actions, BB, CatchAction->getStartBlock());
-
- // When the source program contains multiple nested try blocks the catch
- // handlers can get strung together in such a way that we can encounter
- // a dispatch for a selector that we've already had a handler for.
- if (CatchAction->getSelector()->stripPointerCasts() == ExpectedSelector) {
- ++HandlersFound;
-
- // Add the catch handler to the action list.
- DEBUG(dbgs() << " Found catch dispatch in block "
- << CatchAction->getStartBlock()->getName() << "\n");
- Actions.insertCatchHandler(CatchAction);
- } else {
- // Under some circumstances optimized IR will flow unconditionally into a
- // handler block without checking the selector. This can only happen if
- // the landing pad has a catch-all handler and the handler for the
- // preceeding catch clause is identical to the catch-call handler
- // (typically an empty catch). In this case, the handler must be shared
- // by all remaining clauses.
- if (isa<ConstantPointerNull>(
- CatchAction->getSelector()->stripPointerCasts())) {
- DEBUG(dbgs() << " Applying early catch-all handler in block "
- << CatchAction->getStartBlock()->getName()
- << " to all remaining clauses.\n");
- Actions.insertCatchHandler(CatchAction);
- return;
- }
-
- DEBUG(dbgs() << " Found extra catch dispatch in block "
- << CatchAction->getStartBlock()->getName() << "\n");
- }
-
- // Move on to the block after the catch handler.
- BB = NextBB;
- }
-
- // If we didn't wind up in a catch-all, see if there is any interesting code
- // executed before the resume.
- findCleanupHandlers(Actions, BB, BB);
-
- // It's possible that some optimization moved code into a landingpad that
- // wasn't
- // previously being used for cleanup. If that happens, we need to execute
- // that
- // extra code from a cleanup handler.
- if (Actions.includesCleanup() && !LPad->isCleanup())
- LPad->setCleanup(true);
-}
-
-// This function searches starting with the input block for the next
-// block that terminates with a branch whose condition is based on a selector
-// comparison. This may be the input block. See the mapLandingPadBlocks
-// comments for a discussion of control flow assumptions.
-//
-CatchHandler *WinEHPrepare::findCatchHandler(BasicBlock *BB,
- BasicBlock *&NextBB,
- VisitedBlockSet &VisitedBlocks) {
- // See if we've already found a catch handler use it.
- // Call count() first to avoid creating a null entry for blocks
- // we haven't seen before.
- if (CatchHandlerMap.count(BB) && CatchHandlerMap[BB] != nullptr) {
- CatchHandler *Action = cast<CatchHandler>(CatchHandlerMap[BB]);
- NextBB = Action->getNextBB();
- return Action;
- }
-
- // VisitedBlocks applies only to the current search. We still
- // need to consider blocks that we've visited while mapping other
- // landing pads.
- VisitedBlocks.insert(BB);
-
- BasicBlock *CatchBlock = nullptr;
- Constant *Selector = nullptr;
-
- // If this is the first time we've visited this block from any landing pad
- // look to see if it is a selector dispatch block.
- if (!CatchHandlerMap.count(BB)) {
- if (isSelectorDispatch(BB, CatchBlock, Selector, NextBB)) {
- CatchHandler *Action = new CatchHandler(BB, Selector, NextBB);
- CatchHandlerMap[BB] = Action;
- return Action;
- }
- // If we encounter a block containing an llvm.eh.begincatch before we
- // find a selector dispatch block, the handler is assumed to be
- // reached unconditionally. This happens for catch-all blocks, but
- // it can also happen for other catch handlers that have been combined
- // with the catch-all handler during optimization.
- if (isCatchBlock(BB)) {
- PointerType *Int8PtrTy = Type::getInt8PtrTy(BB->getContext());
- Constant *NullSelector = ConstantPointerNull::get(Int8PtrTy);
- CatchHandler *Action = new CatchHandler(BB, NullSelector, nullptr);
- CatchHandlerMap[BB] = Action;
- return Action;
- }
- }
-
- // Visit each successor, looking for the dispatch.
- // FIXME: We expect to find the dispatch quickly, so this will probably
- // work better as a breadth first search.
- for (BasicBlock *Succ : successors(BB)) {
- if (VisitedBlocks.count(Succ))
- continue;
-
- CatchHandler *Action = findCatchHandler(Succ, NextBB, VisitedBlocks);
- if (Action)
- return Action;
- }
- return nullptr;
-}
-
-// These are helper functions to combine repeated code from findCleanupHandlers.
-static void createCleanupHandler(LandingPadActions &Actions,
- CleanupHandlerMapTy &CleanupHandlerMap,
- BasicBlock *BB) {
- CleanupHandler *Action = new CleanupHandler(BB);
- CleanupHandlerMap[BB] = Action;
- Actions.insertCleanupHandler(Action);
- DEBUG(dbgs() << " Found cleanup code in block "
- << Action->getStartBlock()->getName() << "\n");
-}
-
-static CallSite matchOutlinedFinallyCall(BasicBlock *BB,
- Instruction *MaybeCall) {
- // Look for finally blocks that Clang has already outlined for us.
- // %fp = call i8* @llvm.localaddress()
- // call void @"fin$parent"(iN 1, i8* %fp)
- if (isLocalAddressCall(MaybeCall) && MaybeCall != BB->getTerminator())
- MaybeCall = MaybeCall->getNextNode();
- CallSite FinallyCall(MaybeCall);
- if (!FinallyCall || FinallyCall.arg_size() != 2)
- return CallSite();
- if (!match(FinallyCall.getArgument(0), m_SpecificInt(1)))
- return CallSite();
- if (!isLocalAddressCall(FinallyCall.getArgument(1)))
- return CallSite();
- return FinallyCall;
-}
-
-static BasicBlock *followSingleUnconditionalBranches(BasicBlock *BB) {
- // Skip single ubr blocks.
- while (BB->getFirstNonPHIOrDbg() == BB->getTerminator()) {
- auto *Br = dyn_cast<BranchInst>(BB->getTerminator());
- if (Br && Br->isUnconditional())
- BB = Br->getSuccessor(0);
- else
- return BB;