summaryrefslogtreecommitdiffstats
path: root/llvm/lib/CodeGen/WinEHPrepare.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/CodeGen/WinEHPrepare.cpp')
-rw-r--r--llvm/lib/CodeGen/WinEHPrepare.cpp181
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
OpenPOWER on IntegriCloud