diff options
Diffstat (limited to 'llvm/lib/CodeGen/WinEHPrepare.cpp')
-rw-r--r-- | llvm/lib/CodeGen/WinEHPrepare.cpp | 181 |
1 files changed, 118 insertions, 63 deletions
diff --git a/llvm/lib/CodeGen/WinEHPrepare.cpp b/llvm/lib/CodeGen/WinEHPrepare.cpp index b2945a1074c..6f8c905201d 100644 --- a/llvm/lib/CodeGen/WinEHPrepare.cpp +++ b/llvm/lib/CodeGen/WinEHPrepare.cpp @@ -98,7 +98,8 @@ private: void mapLandingPadBlocks(LandingPadInst *LPad, LandingPadActions &Actions); CatchHandler *findCatchHandler(BasicBlock *BB, BasicBlock *&NextBB, VisitedBlockSet &VisitedBlocks); - CleanupHandler *findCleanupHandler(BasicBlock *StartBB, BasicBlock *EndBB); + void findCleanupHandlers(LandingPadActions &Actions, BasicBlock *StartBB, + BasicBlock *EndBB); void processSEHCatchHandler(CatchHandler *Handler, BasicBlock *StartBB); @@ -402,6 +403,7 @@ bool WinEHPrepare::prepareExceptionHandlers( LandingPadActions Actions; mapLandingPadBlocks(LPad, Actions); + HandlersOutlined |= !Actions.actions().empty(); for (ActionHandler *Action : Actions) { if (Action->hasBeenProcessed()) continue; @@ -413,19 +415,12 @@ bool WinEHPrepare::prepareExceptionHandlers( if (isAsynchronousEHPersonality(Personality)) { if (auto *CatchAction = dyn_cast<CatchHandler>(Action)) { processSEHCatchHandler(CatchAction, StartBB); - HandlersOutlined = true; continue; } } - if (outlineHandler(Action, &F, LPad, StartBB, FrameVarInfo)) { - HandlersOutlined = true; - } - } // End for each Action - - // FIXME: We need a guard against partially outlined functions. - if (!HandlersOutlined) - continue; + outlineHandler(Action, &F, LPad, StartBB, FrameVarInfo); + } // Replace the landing pad with a new llvm.eh.action based landing pad. BasicBlock *NewLPadBB = BasicBlock::Create(Context, "lpad", &F, LPadBB); @@ -1340,13 +1335,7 @@ void WinEHPrepare::mapLandingPadBlocks(LandingPadInst *LPad, DEBUG(dbgs() << "Mapping landing pad: " << BB->getName() << "\n"); if (NumClauses == 0) { - // This landing pad contains only cleanup code. - CleanupHandler *Action = new CleanupHandler(BB); - CleanupHandlerMap[BB] = Action; - Actions.insertCleanupHandler(Action); - DEBUG(dbgs() << " Assuming cleanup code in block " << BB->getName() - << "\n"); - assert(LPad->isCleanup()); + findCleanupHandlers(Actions, BB, nullptr); return; } @@ -1366,14 +1355,8 @@ void WinEHPrepare::mapLandingPadBlocks(LandingPadInst *LPad, // 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) { - if (auto *CleanupAction = findCleanupHandler(BB, BB)) { - // Add a cleanup entry to the list - Actions.insertCleanupHandler(CleanupAction); - DEBUG(dbgs() << " Found cleanup code in block " - << CleanupAction->getStartBlock()->getName() << "\n"); - } - } + if (Personality == EHPersonality::MSVC_CXX) + findCleanupHandlers(Actions, BB, BB); // Add the catch handler to the action list. CatchHandler *Action = @@ -1390,13 +1373,7 @@ void WinEHPrepare::mapLandingPadBlocks(LandingPadInst *LPad, CatchHandler *CatchAction = findCatchHandler(BB, NextBB, VisitedBlocks); // See if there is any interesting code executed before the dispatch. - if (auto *CleanupAction = - findCleanupHandler(BB, CatchAction->getStartBlock())) { - // Add a cleanup entry to the list - Actions.insertCleanupHandler(CleanupAction); - DEBUG(dbgs() << " Found cleanup code in block " - << CleanupAction->getStartBlock()->getName() << "\n"); - } + findCleanupHandlers(Actions, BB, CatchAction->getStartBlock()); assert(CatchAction); ++HandlersFound; @@ -1412,12 +1389,7 @@ void WinEHPrepare::mapLandingPadBlocks(LandingPadInst *LPad, // If we didn't wind up in a catch-all, see if there is any interesting code // executed before the resume. - if (auto *CleanupAction = findCleanupHandler(BB, BB)) { - // Add a cleanup entry to the list - Actions.insertCleanupHandler(CleanupAction); - DEBUG(dbgs() << " Found cleanup code in block " - << CleanupAction->getStartBlock()->getName() << "\n"); - } + findCleanupHandlers(Actions, BB, BB); // It's possible that some optimization moved code into a landingpad that // wasn't @@ -1477,20 +1449,56 @@ CatchHandler *WinEHPrepare::findCatchHandler(BasicBlock *BB, return nullptr; } -// These are helper functions to combine repeated code from findCleanupHandler. -static CleanupHandler * -createCleanupHandler(CleanupHandlerMapTy &CleanupHandlerMap, BasicBlock *BB) { +// 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; - return Action; + Actions.insertCleanupHandler(Action); + DEBUG(dbgs() << " Found cleanup code in block " + << Action->getStartBlock()->getName() << "\n"); +} + +static bool isFrameAddressCall(Value *V) { + return match(V, m_Intrinsic<Intrinsic::frameaddress>(m_SpecificInt(0))); +} + +static CallSite matchOutlinedFinallyCall(BasicBlock *BB, + Instruction *MaybeCall) { + // Look for finally blocks that Clang has already outlined for us. + // %fp = call i8* @llvm.frameaddress(i32 0) + // call void @"fin$parent"(iN 1, i8* %fp) + if (isFrameAddressCall(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 (!isFrameAddressCall(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; + } + return BB; } // This function searches starting with the input block for the next block that // contains code that is not part of a catch handler and would not be eliminated // during handler outlining. // -CleanupHandler *WinEHPrepare::findCleanupHandler(BasicBlock *StartBB, - BasicBlock *EndBB) { +void WinEHPrepare::findCleanupHandlers(LandingPadActions &Actions, + BasicBlock *StartBB, BasicBlock *EndBB) { // Here we will skip over the following: // // landing pad prolog: @@ -1507,6 +1515,7 @@ CleanupHandler *WinEHPrepare::findCleanupHandler(BasicBlock *StartBB, // Anything other than an unconditional branch will kick us out of this loop // one way or another. while (BB) { + BB = followSingleUnconditionalBranches(BB); // If we've already scanned this block, don't scan it again. If it is // a cleanup block, there will be an action in the CleanupHandlerMap. // If we've scanned it and it is not a cleanup block, there will be a @@ -1515,7 +1524,12 @@ CleanupHandler *WinEHPrepare::findCleanupHandler(BasicBlock *StartBB, // avoid creating a null entry for blocks we haven't scanned. if (CleanupHandlerMap.count(BB)) { if (auto *Action = CleanupHandlerMap[BB]) { - return cast<CleanupHandler>(Action); + Actions.insertCleanupHandler(Action); + DEBUG(dbgs() << " Found cleanup code in block " + << Action->getStartBlock()->getName() << "\n"); + // FIXME: This cleanup might chain into another, and we need to discover + // that. + return; } else { // Here we handle the case where the cleanup handler map contains a // value for this block but the value is a nullptr. This means that @@ -1527,11 +1541,9 @@ CleanupHandler *WinEHPrepare::findCleanupHandler(BasicBlock *StartBB, // would terminate the search for cleanup code, so the unconditional // branch is the only case for which we might need to continue // searching. - if (BB == EndBB) - return nullptr; - BasicBlock *SuccBB; - if (!match(BB->getTerminator(), m_UnconditionalBr(SuccBB))) - return nullptr; + BasicBlock *SuccBB = followSingleUnconditionalBranches(BB); + if (SuccBB == BB || SuccBB == EndBB) + return; BB = SuccBB; continue; } @@ -1564,14 +1576,14 @@ CleanupHandler *WinEHPrepare::findCleanupHandler(BasicBlock *StartBB, // If there is only one landingpad, we may use the lpad directly with no // insertions. if (isa<LandingPadInst>(ResumeVal)) - return nullptr; + return; if (!isa<PHINode>(ResumeVal)) { Insert2 = dyn_cast<InsertValueInst>(ResumeVal); if (!Insert2) - return createCleanupHandler(CleanupHandlerMap, BB); + return createCleanupHandler(Actions, CleanupHandlerMap, BB); Insert1 = dyn_cast<InsertValueInst>(Insert2->getAggregateOperand()); if (!Insert1) - return createCleanupHandler(CleanupHandlerMap, BB); + return createCleanupHandler(Actions, CleanupHandlerMap, BB); } for (BasicBlock::iterator II = BB->getFirstNonPHIOrDbg(), IE = BB->end(); II != IE; ++II) { @@ -1582,10 +1594,10 @@ CleanupHandler *WinEHPrepare::findCleanupHandler(BasicBlock *StartBB, continue; if (!Inst->hasOneUse() || (Inst->user_back() != Insert1 && Inst->user_back() != Insert2)) { - return createCleanupHandler(CleanupHandlerMap, BB); + return createCleanupHandler(Actions, CleanupHandlerMap, BB); } } - return nullptr; + return; } BranchInst *Branch = dyn_cast<BranchInst>(Terminator); @@ -1596,7 +1608,7 @@ CleanupHandler *WinEHPrepare::findCleanupHandler(BasicBlock *StartBB, // br i1 %matches, label %catch14, label %eh.resume CmpInst *Compare = dyn_cast<CmpInst>(Branch->getCondition()); if (!Compare || !Compare->isEquality()) - return createCleanupHandler(CleanupHandlerMap, BB); + return createCleanupHandler(Actions, CleanupHandlerMap, BB); for (BasicBlock::iterator II = BB->getFirstNonPHIOrDbg(), IE = BB->end(); II != IE; ++II) { Instruction *Inst = II; @@ -1606,11 +1618,54 @@ CleanupHandler *WinEHPrepare::findCleanupHandler(BasicBlock *StartBB, continue; if (match(Inst, m_Intrinsic<Intrinsic::eh_typeid_for>())) continue; - return createCleanupHandler(CleanupHandlerMap, BB); + return createCleanupHandler(Actions, CleanupHandlerMap, BB); } // The selector dispatch block should always terminate our search. assert(BB == EndBB); - return nullptr; + return; + } + + if (isAsynchronousEHPersonality(Personality)) { + // If this is a landingpad block, split the block at the first non-landing + // pad instruction. + Instruction *MaybeCall = BB->getFirstNonPHIOrDbg(); + if (LPadMap) { + while (MaybeCall != BB->getTerminator() && + LPadMap->isLandingPadSpecificInst(MaybeCall)) + MaybeCall = MaybeCall->getNextNode(); + } + + // Look for outlined finally calls. + if (CallSite FinallyCall = matchOutlinedFinallyCall(BB, MaybeCall)) { + Function *Fin = FinallyCall.getCalledFunction(); + assert(Fin && "outlined finally call should be direct"); + auto *Action = new CleanupHandler(BB); + Action->setHandlerBlockOrFunc(Fin); + Actions.insertCleanupHandler(Action); + CleanupHandlerMap[BB] = Action; + DEBUG(dbgs() << " Found frontend-outlined finally call to " + << Fin->getName() << " in block " + << Action->getStartBlock()->getName() << "\n"); + + // Split the block if there were more interesting instructions and look + // for finally calls in the normal successor block. + BasicBlock *SuccBB = BB; + if (FinallyCall.getInstruction() != BB->getTerminator() && + FinallyCall.getInstruction()->getNextNode() != BB->getTerminator()) { + SuccBB = BB->splitBasicBlock(FinallyCall.getInstruction()->getNextNode()); + } else { + if (FinallyCall.isInvoke()) { + SuccBB = cast<InvokeInst>(FinallyCall.getInstruction())->getNormalDest(); + } else { + SuccBB = BB->getUniqueSuccessor(); + assert(SuccBB && "splitOutlinedFinallyCalls didn't insert a branch"); + } + } + BB = SuccBB; + if (BB == EndBB) + return; + continue; + } } // Anything else is either a catch block or interesting cleanup code. @@ -1624,21 +1679,21 @@ CleanupHandler *WinEHPrepare::findCleanupHandler(BasicBlock *StartBB, continue; // If this is a catch block, there is no cleanup code to be found. if (match(Inst, m_Intrinsic<Intrinsic::eh_begincatch>())) - return nullptr; + return; // If this a nested landing pad, it may contain an endcatch call. if (match(Inst, m_Intrinsic<Intrinsic::eh_endcatch>())) - return nullptr; + return; // Anything else makes this interesting cleanup code. - return createCleanupHandler(CleanupHandlerMap, BB); + return createCleanupHandler(Actions, CleanupHandlerMap, BB); } // Only unconditional branches in empty blocks should get this far. assert(Branch && Branch->isUnconditional()); if (BB == EndBB) - return nullptr; + return; BB = Branch->getSuccessor(0); } - return nullptr; + return; } // This is a public function, declared in WinEHFuncInfo.h and is also |