[PATCH] Fix WinEHPrepare bug with multiple catch handlers
Andy Kaylor
andrew.kaylor at intel.com
Mon Mar 30 13:35:13 PDT 2015
Adding a fix for an unrelated problem where an llvm.eh.endcatch call is not immediately followed by an unconditional branch instruction:
define void @f() {
entry:
invoke void @f() to label %try.cont unwind label %lpad
lpad: ; preds = %entry
%0 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
catch i8* null
%1 = extractvalue { i8*, i32 } %0, 0
tail call void @llvm.eh.begincatch(i8* %1, i8* null) #0
tail call void @llvm.eh.endcatch() #0
ret void
try.cont: ; preds = %entry
ret void
}
I considered splitting the block in the mapLandingPadBlocks code, but that involved extra searching for the endcatch calls, while this code already has the needed location.
REPOSITORY
rL LLVM
http://reviews.llvm.org/D8682
Files:
lib/CodeGen/WinEHPrepare.cpp
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<CmpInst>(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<LoadInst>(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<BranchInst>(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<BranchInst>(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<BasicBlock *>(ParentBB),
+ const_cast<IntrinsicInst *>(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<LoadInst>(Inst)) {
+ for (auto *U : Load->users()) {
+ if (cast<Instruction>(U)->getParent() == BB && U != Compare)
+ return createCleanupHandler(CleanupHandlerMap, BB);
+ }
+ continue;
+ }
if (match(Inst, m_Intrinsic<Intrinsic::eh_typeid_for>()))
continue;
- if (!isa<LoadInst>(Inst))
- return createCleanupHandler(CleanupHandlerMap, BB);
+ return createCleanupHandler(CleanupHandlerMap, BB);
}
// The selector dispatch block should always terminate our search.
assert(BB == EndBB);
EMAIL PREFERENCES
http://reviews.llvm.org/settings/panel/emailpreferences/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D8682.22903.patch
Type: text/x-patch
Size: 4524 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20150330/6d2eecf1/attachment.bin>
More information about the llvm-commits
mailing list