[llvm] r252279 - Revert r252249 (and r252255, r252258), "[WinEH] Clone funclets with multiple parents"
NAKAMURA Takumi via llvm-commits
llvm-commits at lists.llvm.org
Fri Nov 6 02:07:33 PST 2015
Author: chapuni
Date: Fri Nov 6 04:07:33 2015
New Revision: 252279
URL: http://llvm.org/viewvc/llvm-project?rev=252279&view=rev
Log:
Revert r252249 (and r252255, r252258), "[WinEH] Clone funclets with multiple parents"
It behaved flaky due to iterating pointer key values on std::set and std::map.
Removed:
llvm/trunk/test/CodeGen/WinEH/wineh-multi-parent-cloning.ll
Modified:
llvm/trunk/lib/AsmParser/LLParser.cpp
llvm/trunk/lib/CodeGen/WinEHPrepare.cpp
llvm/trunk/test/CodeGen/WinEH/wineh-cloning.ll
llvm/trunk/test/CodeGen/WinEH/wineh-demotion.ll
llvm/trunk/test/CodeGen/WinEH/wineh-no-demotion.ll
Modified: llvm/trunk/lib/AsmParser/LLParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLParser.cpp?rev=252279&r1=252278&r2=252279&view=diff
==============================================================================
--- llvm/trunk/lib/AsmParser/LLParser.cpp (original)
+++ llvm/trunk/lib/AsmParser/LLParser.cpp Fri Nov 6 04:07:33 2015
@@ -5322,8 +5322,7 @@ bool LLParser::ParseCleanupEndPad(Instru
if (Lex.getKind() == lltok::kw_caller) {
Lex.Lex();
} else {
- return Error(Lex.getLoc(),
- "'to' must be followed by 'caller' in catchendpad");
+ return true;
}
} else {
if (ParseTypeAndBasicBlock(UnwindBB, PFS)) {
Modified: llvm/trunk/lib/CodeGen/WinEHPrepare.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/WinEHPrepare.cpp?rev=252279&r1=252278&r2=252279&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/WinEHPrepare.cpp (original)
+++ llvm/trunk/lib/CodeGen/WinEHPrepare.cpp Fri Nov 6 04:07:33 2015
@@ -74,20 +74,6 @@ private:
SmallVectorImpl<BasicBlock *> &EntryBlocks);
void replaceTerminatePadWithCleanup(Function &F);
void colorFunclets(Function &F, SmallVectorImpl<BasicBlock *> &EntryBlocks);
- void resolveFuncletAncestry(Function &F,
- SmallVectorImpl<BasicBlock *> &EntryBlocks);
- void resolveFuncletAncestryForPath(
- Function &F, SmallVectorImpl<BasicBlock *> &FuncletPath,
- std::map<BasicBlock *, BasicBlock *> &IdentityMap);
- void makeFuncletEdgeUnreachable(BasicBlock *Parent, BasicBlock *Child);
- BasicBlock *cloneFuncletForParent(Function &F, BasicBlock *FuncletEntry,
- BasicBlock *Parent);
- void updateTerminatorsAfterFuncletClone(
- Function &F, BasicBlock *OrigFunclet, BasicBlock *CloneFunclet,
- BasicBlock *OrigBlock, BasicBlock *CloneBlock, BasicBlock *CloneParent,
- ValueToValueMapTy &VMap,
- std::map<BasicBlock *, BasicBlock *> &Orig2Clone);
-
void demotePHIsOnFunclets(Function &F);
void demoteUsesBetweenFunclets(Function &F);
void demoteArgumentUses(Function &F);
@@ -102,18 +88,7 @@ private:
std::map<BasicBlock *, std::set<BasicBlock *>> BlockColors;
std::map<BasicBlock *, std::set<BasicBlock *>> FuncletBlocks;
- std::map<BasicBlock *, std::vector<BasicBlock *>> FuncletChildren;
- std::map<BasicBlock *, std::vector<BasicBlock *>> FuncletParents;
-
- // This is a flag that indicates an uncommon situation where we need to
- // clone funclets has been detected.
- bool FuncletCloningRequired = false;
- // When a funclet with multiple parents contains a catchret, the block to
- // which it returns will be cloned so that there is a copy in each parent
- // but one of the copies will not be properly linked to the catchret and
- // in most cases will have no predecessors. This double map allows us
- // to find these cloned blocks when we clone the child funclet.
- std::map<BasicBlock *, std::map<BasicBlock *, BasicBlock*>> EstrangedBlocks;
+ std::map<BasicBlock *, std::set<BasicBlock *>> FuncletChildren;
};
} // end anonymous namespace
@@ -584,7 +559,8 @@ void WinEHPrepare::replaceTerminatePadWi
static void
colorFunclets(Function &F, SmallVectorImpl<BasicBlock *> &EntryBlocks,
std::map<BasicBlock *, std::set<BasicBlock *>> &BlockColors,
- std::map<BasicBlock *, std::set<BasicBlock *>> &FuncletBlocks) {
+ std::map<BasicBlock *, std::set<BasicBlock *>> &FuncletBlocks,
+ std::map<BasicBlock *, std::set<BasicBlock *>> &FuncletChildren) {
SmallVector<std::pair<BasicBlock *, BasicBlock *>, 16> Worklist;
BasicBlock *EntryBlock = &F.getEntryBlock();
@@ -601,18 +577,12 @@ colorFunclets(Function &F, SmallVectorIm
// are as defined above. A post-pass fixes up the block color map to reflect
// the same sense of "color" for funclet entries as for other blocks.
- DEBUG_WITH_TYPE("winehprepare-coloring", dbgs() << "\nColoring funclets for "
- << F.getName() << "\n");
-
Worklist.push_back({EntryBlock, EntryBlock});
while (!Worklist.empty()) {
BasicBlock *Visiting;
BasicBlock *Color;
std::tie(Visiting, Color) = Worklist.pop_back_val();
- DEBUG_WITH_TYPE("winehprepare-coloring",
- dbgs() << "Visiting " << Visiting->getName() << ", "
- << Color->getName() << "\n");
Instruction *VisitingHead = Visiting->getFirstNonPHI();
if (VisitingHead->isEHPad() && !isa<CatchEndPadInst>(VisitingHead) &&
!isa<CleanupEndPadInst>(VisitingHead)) {
@@ -630,13 +600,8 @@ colorFunclets(Function &F, SmallVectorIm
if (auto *Exit = dyn_cast<TerminatorInst>(U)) {
for (BasicBlock *Succ : successors(Exit->getParent()))
if (!isa<CatchEndPadInst>(*Succ->getFirstNonPHI()))
- if (BlockColors[Succ].insert(Color).second) {
- DEBUG_WITH_TYPE("winehprepare-coloring",
- dbgs() << " Assigned color \'"
- << Color->getName() << "\' to block \'"
- << Succ->getName() << "\'.\n");
+ if (BlockColors[Succ].insert(Color).second)
Worklist.push_back({Succ, Color});
- }
}
}
// Handle CatchPad specially since its successors need different colors.
@@ -645,18 +610,10 @@ colorFunclets(Function &F, SmallVectorIm
// visit the unwind successor with the color of the parent.
BasicBlock *NormalSucc = CatchPad->getNormalDest();
if (BlockColors[NormalSucc].insert(Visiting).second) {
- DEBUG_WITH_TYPE("winehprepare-coloring",
- dbgs() << " Assigned color \'" << Visiting->getName()
- << "\' to block \'" << NormalSucc->getName()
- << "\'.\n");
Worklist.push_back({NormalSucc, Visiting});
}
BasicBlock *UnwindSucc = CatchPad->getUnwindDest();
if (BlockColors[UnwindSucc].insert(Color).second) {
- DEBUG_WITH_TYPE("winehprepare-coloring",
- dbgs() << " Assigned color \'" << Color->getName()
- << "\' to block \'" << UnwindSucc->getName()
- << "\'.\n");
Worklist.push_back({UnwindSucc, Color});
}
continue;
@@ -688,806 +645,10 @@ colorFunclets(Function &F, SmallVectorIm
continue;
}
if (BlockColors[Succ].insert(Color).second) {
- DEBUG_WITH_TYPE("winehprepare-coloring",
- dbgs() << " Assigned color \'" << Color->getName()
- << "\' to block \'" << Succ->getName()
- << "\'.\n");
Worklist.push_back({Succ, Color});
}
}
}
-}
-
-static BasicBlock *getEndPadForCatch(CatchPadInst *Catch) {
- // The catch may have sibling catches. Follow the unwind chain until we get
- // to the catchendpad.
- BasicBlock *NextUnwindDest = Catch->getUnwindDest();
- auto *UnwindTerminator = NextUnwindDest->getTerminator();
- while (auto *NextCatch = dyn_cast<CatchPadInst>(UnwindTerminator)) {
- NextUnwindDest = NextCatch->getUnwindDest();
- UnwindTerminator = NextUnwindDest->getTerminator();
- }
- // The last catch in the chain must unwind to a catchendpad.
- assert(isa<CatchEndPadInst>(UnwindTerminator));
- return NextUnwindDest;
-}
-
-static void updateClonedEHPadUnwindToParent(
- BasicBlock *UnwindDest, BasicBlock *OrigBlock, BasicBlock *CloneBlock,
- std::vector<BasicBlock *> &OrigParents, BasicBlock *CloneParent) {
- auto updateUnwindTerminator = [](BasicBlock *BB) {
- auto *Terminator = BB->getTerminator();
- if (isa<CatchEndPadInst>(Terminator) ||
- isa<CleanupEndPadInst>(Terminator)) {
- removeUnwindEdge(BB);
- } else {
- // If the block we're updating has a cleanupendpad or cleanupret
- // terminator, we just want to replace that terminator with an
- // unreachable instruction.
- assert(isa<CleanupEndPadInst>(Terminator) ||
- isa<CleanupReturnInst>(Terminator));
- // Loop over all of the successors, removing the block's entry from any
- // PHI nodes.
- for (succ_iterator SI = succ_begin(BB), SE = succ_end(BB); SI != SE; ++SI)
- (*SI)->removePredecessor(BB);
- // Remove the terminator and replace it with an unreachable instruction.
- BB->getTerminator()->eraseFromParent();
- new UnreachableInst(BB->getContext(), BB);
- }
- };
-
- assert(UnwindDest->isEHPad());
- // There are many places to which this EH terminator can unwind and each has
- // slightly different rules for whether or not it fits with the given
- // location.
- auto *EHPadInst = UnwindDest->getFirstNonPHI();
- if (isa<CatchEndPadInst>(EHPadInst)) {
- auto *CloneParentCatch =
- dyn_cast<CatchPadInst>(CloneParent->getFirstNonPHI());
- if (!CloneParentCatch ||
- getEndPadForCatch(CloneParentCatch) != UnwindDest) {
- DEBUG_WITH_TYPE(
- "winehprepare-coloring",
- dbgs() << " removing unwind destination of clone block \'"
- << CloneBlock->getName() << "\'.\n");
- updateUnwindTerminator(CloneBlock);
- }
- // It's possible that the catch end pad is a legal match for both the clone
- // and the original, so they must be checked separately. If the original
- // funclet will still have multiple parents after the current clone parent
- // is removed, we'll leave its unwind terminator until later.
- assert(OrigParents.size() >= 2);
- if (OrigParents.size() != 2)
- return;
-
- // If the original funclet will have a single parent after the clone parent
- // is removed, check that parent's unwind destination.
- assert(OrigParents.front() == CloneParent ||
- OrigParents.back() == CloneParent);
- BasicBlock *OrigParent;
- if (OrigParents.front() == CloneParent)
- OrigParent = OrigParents.back();
- else
- OrigParent = OrigParents.front();
-
- auto *OrigParentCatch =
- dyn_cast<CatchPadInst>(OrigParent->getFirstNonPHI());
- if (!OrigParentCatch || getEndPadForCatch(OrigParentCatch) != UnwindDest) {
- DEBUG_WITH_TYPE(
- "winehprepare-coloring",
- dbgs() << " removing unwind destination of original block \'"
- << OrigBlock << "\'.\n");
- updateUnwindTerminator(OrigBlock);
- }
- } else if (auto *CleanupEnd = dyn_cast<CleanupEndPadInst>(EHPadInst)) {
- // If the EH terminator unwinds to a cleanupendpad, that cleanupendpad
- // must be ending a cleanuppad of either our clone parent or one
- // one of the parents of the original funclet.
- auto *CloneParentCP =
- dyn_cast<CleanupPadInst>(CloneParent->getFirstNonPHI());
- auto *EndedCP = CleanupEnd->getCleanupPad();
- if (EndedCP == CloneParentCP) {
- // If it is ending the cleanuppad of our cloned parent, then we
- // want to remove the unwind destination of the EH terminator that
- // we associated with the original funclet.
- assert(isa<CatchEndPadInst>(OrigBlock->getFirstNonPHI()));
- DEBUG_WITH_TYPE(
- "winehprepare-coloring",
- dbgs() << " removing unwind destination of original block \'"
- << OrigBlock->getName() << "\'.\n");
- updateUnwindTerminator(OrigBlock);
- } else {
- // If it isn't ending the cleanuppad of our clone parent, then we
- // want to remove the unwind destination of the EH terminator that
- // associated with our cloned funclet.
- assert(isa<CatchEndPadInst>(CloneBlock->getFirstNonPHI()));
- DEBUG_WITH_TYPE(
- "winehprepare-coloring",
- dbgs() << " removing unwind destination of clone block \'"
- << CloneBlock->getName() << "\'.\n");
- updateUnwindTerminator(CloneBlock);
- }
- } else {
- // If the EH terminator unwinds to a catchpad, cleanuppad or
- // terminatepad that EH pad must be a sibling of the funclet we're
- // cloning. We'll clone it later and update one of the catchendpad
- // instrunctions that unwinds to it at that time.
- assert(isa<CatchPadInst>(EHPadInst) || isa<CleanupPadInst>(EHPadInst) ||
- isa<TerminatePadInst>(EHPadInst));
- }
-}
-
-// If the terminator is a catchpad, we must also clone the catchendpad to which
-// it unwinds and add this to the clone parent's block list. The catchendpad
-// unwinds to either its caller, a sibling EH pad, a cleanup end pad in its
-// parent funclet or a catch end pad in its grandparent funclet (which must be
-// coupled with the parent funclet). If it has no unwind destination
-// (i.e. unwind to caller), there is nothing to be done. If the unwind
-// destination is a sibling EH pad, we will update the terminators later (in
-// resolveFuncletAncestryForPath). If it unwinds to a cleanup end pad or a
-// catch end pad and this end pad corresponds to the clone parent, we will
-// remove the unwind destination in the original catchendpad. If it unwinds to
-// a cleanup end pad or a catch end pad that does not correspond to the clone
-// parent, we will remove the unwind destination in the cloned catchendpad.
-static void updateCatchTerminators(
- Function &F, CatchPadInst *OrigCatch, CatchPadInst *CloneCatch,
- std::vector<BasicBlock *> &OrigParents, BasicBlock *CloneParent,
- ValueToValueMapTy &VMap,
- std::map<BasicBlock *, std::set<BasicBlock *>> &BlockColors,
- std::map<BasicBlock *, std::set<BasicBlock *>> &FuncletBlocks) {
- // If we're cloning a catch pad that unwinds to a catchendpad, we also
- // need to clone the catchendpad. The coloring algorithm associates
- // the catchendpad block with the funclet's parent, so we have some work
- // to do here to figure out whether the original belongs to the clone
- // parent or one of the original funclets other parents (it might have
- // more than one at this point). In either case, we might also need to
- // remove the unwind edge if the catchendpad doesn't unwind to a block
- // in the right grandparent funclet.
- Instruction *I = CloneCatch->getUnwindDest()->getFirstNonPHI();
- if (auto *CEP = dyn_cast<CatchEndPadInst>(I)) {
- assert(BlockColors[CEP->getParent()].size() == 1);
- BasicBlock *CEPFunclet = *(BlockColors[CEP->getParent()].begin());
- BasicBlock *CEPCloneParent = nullptr;
- CatchPadInst *PredCatch = nullptr;
- if (CEPFunclet == CloneParent) {
- // The catchendpad is in the clone parent, so we need to clone it
- // and associate the clone with the original funclet's parent. If
- // the original funclet had multiple parents, we'll add it to the
- // first parent that isn't the clone parent. The logic in
- // updateClonedEHPadUnwindToParent() will only remove the unwind edge
- // if there is only one parent other than the clone parent, so we don't
- // need to verify the ancestry. The catchendpad will eventually be
- // cloned into the correct parent and all invalid unwind edges will be
- // removed.
- for (auto *Parent : OrigParents) {
- if (Parent != CloneParent) {
- CEPCloneParent = Parent;
- break;
- }
- }
- PredCatch = OrigCatch;
- } else {
- CEPCloneParent = CloneParent;
- PredCatch = CloneCatch;
- }
- assert(CEPCloneParent && PredCatch);
- DEBUG_WITH_TYPE("winehprepare-coloring",
- dbgs() << " Cloning catchendpad \'"
- << CEP->getParent()->getName() << "\' for funclet \'"
- << CEPCloneParent->getName() << "\'.\n");
- BasicBlock *ClonedCEP = CloneBasicBlock(
- CEP->getParent(), VMap, Twine(".from.", CEPCloneParent->getName()));
- // Insert the clone immediately after the original to ensure determinism
- // and to keep the same relative ordering of any funclet's blocks.
- ClonedCEP->insertInto(&F, CEP->getParent()->getNextNode());
- PredCatch->setUnwindDest(ClonedCEP);
- FuncletBlocks[CEPCloneParent].insert(ClonedCEP);
- BlockColors[ClonedCEP].insert(CEPCloneParent);
- DEBUG_WITH_TYPE("winehprepare-coloring",
- dbgs() << " Assigning color \'"
- << CEPCloneParent->getName() << "\' to block \'"
- << ClonedCEP->getName() << "\'.\n");
- auto *ClonedCEPInst = cast<CatchEndPadInst>(ClonedCEP->getTerminator());
- if (auto *Dest = ClonedCEPInst->getUnwindDest())
- updateClonedEHPadUnwindToParent(Dest, OrigCatch->getUnwindDest(),
- CloneCatch->getUnwindDest(), OrigParents,
- CloneParent);
- }
-}
-
-// While we are cloning a funclet because it has multiple parents, we will call
-// this routine to update the terminators for the original and cloned copies
-// of each basic block. All blocks in the funclet have been clone by this time.
-// OrigBlock and CloneBlock will be identical except for their block label.
-//
-// If the terminator is a catchpad, we must also clone the catchendpad to which
-// it unwinds and in most cases update either the original catchendpad or the
-// clone. See the updateCatchTerminators() helper routine for details.
-//
-// If the terminator is a catchret its successor is a block in its parent
-// funclet. If the instruction returns to a block in the parent for which the
-// cloned funclet was created, the terminator in the original block must be
-// replaced by an unreachable instruction. Otherwise the terminator in the
-// clone block must be replaced by an unreachable instruction.
-//
-// If the terminator is a cleanupret or cleanupendpad it either unwinds to
-// caller or unwinds to a sibling EH pad, a cleanup end pad in its parent
-// funclet or a catch end pad in its grandparent funclet (which must be
-// coupled with the parent funclet). If it unwinds to caller there is
-// nothing to be done. If the unwind destination is a sibling EH pad, we will
-// update the terminators later (in resolveFuncletAncestryForPath). If it
-// unwinds to a cleanup end pad or a catch end pad and this end pad corresponds
-// to the clone parent, we will replace the terminator in the original block
-// with an unreachable instruction. If it unwinds to a cleanup end pad or a
-// catch end pad that does not correspond to the clone parent, we will replace
-// the terminator in the clone block with an unreachable instruction.
-//
-// If the terminator is an invoke instruction, it unwinds either to a child
-// EH pad, a cleanup end pad in the current funclet, or a catch end pad in a
-// parent funclet (which ends either the current catch pad or a sibling
-// catch pad). If it unwinds to a child EH pad, the child will have multiple
-// parents after this funclet is cloned and this case will be handled later in
-// the resolveFuncletAncestryForPath processing. If it unwinds to a
-// cleanup end pad in the current funclet, the instruction remapping during
-// the cloning process should have already mapped the unwind destination to
-// the cloned copy of the cleanup end pad. If it unwinds to a catch end pad
-// there are two possibilities: either the catch end pad is the unwind
-// destination for the catch pad we are currently cloning or it is the unwind
-// destination for a sibling catch pad. If it it the unwind destination of the
-// catch pad we are cloning, we need to update the cloned invoke instruction
-// to unwind to the cloned catch end pad. Otherwise, we will handle this
-// later (in resolveFuncletAncestryForPath).
-void WinEHPrepare::updateTerminatorsAfterFuncletClone(
- Function &F, BasicBlock *OrigFunclet, BasicBlock *CloneFunclet,
- BasicBlock *OrigBlock, BasicBlock *CloneBlock, BasicBlock *CloneParent,
- ValueToValueMapTy &VMap, std::map<BasicBlock *, BasicBlock *> &Orig2Clone) {
- // If the cloned block doesn't have an exceptional terminator, there is
- // nothing to be done here.
- TerminatorInst *CloneTerminator = CloneBlock->getTerminator();
- if (!CloneTerminator->isExceptional())
- return;
-
- if (auto *CloneCatch = dyn_cast<CatchPadInst>(CloneTerminator)) {
- // A cloned catch pad has a lot of wrinkles, so we'll call a helper function
- // to update this case.
- auto *OrigCatch = cast<CatchPadInst>(OrigBlock->getTerminator());
- updateCatchTerminators(F, OrigCatch, CloneCatch,
- FuncletParents[OrigFunclet], CloneParent, VMap,
- BlockColors, FuncletBlocks);
- } else if (auto *CRI = dyn_cast<CatchReturnInst>(CloneTerminator)) {
- if (FuncletBlocks[CloneParent].count(CRI->getSuccessor())) {
- BasicBlock *OrigParent;
- // The original funclet may have more than two parents, but that's OK.
- // We just need to remap the original catchret to any of the parents.
- // All of the parents should have an entry in the EstrangedBlocks map
- // if any of them do.
- if (FuncletParents[OrigFunclet].front() == CloneParent)
- OrigParent = FuncletParents[OrigFunclet].back();
- else
- OrigParent = FuncletParents[OrigFunclet].front();
- for (succ_iterator SI = succ_begin(OrigBlock), SE = succ_end(OrigBlock);
- SI != SE; ++SI)
- (*SI)->removePredecessor(OrigBlock);
- BasicBlock *LostBlock = EstrangedBlocks[OrigParent][CRI->getSuccessor()];
- auto *OrigCatchRet = cast<CatchReturnInst>(OrigBlock->getTerminator());
- if (LostBlock) {
- OrigCatchRet->setSuccessor(LostBlock);
- } else {
- OrigCatchRet->eraseFromParent();
- new UnreachableInst(OrigBlock->getContext(), OrigBlock);
- }
- } else {
- for (succ_iterator SI = succ_begin(CloneBlock), SE = succ_end(CloneBlock);
- SI != SE; ++SI)
- (*SI)->removePredecessor(CloneBlock);
- BasicBlock *LostBlock = EstrangedBlocks[CloneParent][CRI->getSuccessor()];
- if (LostBlock) {
- CRI->setSuccessor(LostBlock);
- } else {
- CRI->eraseFromParent();
- new UnreachableInst(CloneBlock->getContext(), CloneBlock);
- }
- }
- } else if (isa<CleanupReturnInst>(CloneTerminator) ||
- isa<CleanupEndPadInst>(CloneTerminator)) {
- BasicBlock *UnwindDest = nullptr;
-
- // A cleanup pad can unwind through either a cleanupret or a cleanupendpad
- // but both are handled the same way.
- if (auto *CRI = dyn_cast<CleanupReturnInst>(CloneTerminator))
- UnwindDest = CRI->getUnwindDest();
- else if (auto *CEI = dyn_cast<CleanupEndPadInst>(CloneTerminator))
- UnwindDest = CEI->getUnwindDest();
-
- // If the instruction has no local unwind destination, there is nothing
- // to be done.
- if (!UnwindDest)
- return;
-
- // The unwind destination may be a sibling EH pad, a catchendpad in
- // a grandparent funclet (ending a catchpad in the parent) or a cleanup
- // cleanupendpad in the parent. Call a helper routine to diagnose this
- // and remove either the clone or original terminator as needed.
- updateClonedEHPadUnwindToParent(UnwindDest, OrigBlock, CloneBlock,
- FuncletParents[OrigFunclet], CloneParent);
- } else if (auto *II = dyn_cast<InvokeInst>(CloneTerminator)) {
- BasicBlock *UnwindDest = II->getUnwindDest();
- assert(UnwindDest && "Invoke unwinds to a null destination.");
- assert(UnwindDest->isEHPad() && "Invoke does not unwind to an EH pad.");
- auto *EHPadInst = UnwindDest->getFirstNonPHI();
- if (isa<CleanupEndPadInst>(EHPadInst)) {
- // An invoke that unwinds to a cleanup end pad must be in a cleanup pad.
- assert(isa<CleanupPadInst>(CloneFunclet->getFirstNonPHI()) &&
- "Unwinding to cleanup end pad from a non cleanup pad funclet.");
- // The funclet cloning should have remapped the destination to the cloned
- // cleanup end pad.
- assert(FuncletBlocks[CloneFunclet].count(UnwindDest) &&
- "Unwind destination for invoke was not updated during cloning.");
- } else if (isa<CatchEndPadInst>(EHPadInst)) {
- auto *OrigCatch = cast<CatchPadInst>(OrigFunclet->getFirstNonPHI());
- auto *CloneCatch = cast<CatchPadInst>(CloneFunclet->getFirstNonPHI());
- if (OrigCatch->getUnwindDest() == UnwindDest) {
- // If the invoke unwinds to a catch end pad that is the unwind
- // destination for the original catch pad, the cloned invoke should
- // unwind to the cloned catch end pad.
- II->setUnwindDest(CloneCatch->getUnwindDest());
- } else if (CloneCatch->getUnwindDest() == UnwindDest) {
- // If the invoke unwinds to a catch end pad that is the unwind
- // destination for the clone catch pad, the original invoke should
- // unwind to the unwind destination of the original catch pad.
- // This happens when the catch end pad is matched to the clone
- // parent when the catchpad instruction is cloned and the original
- // invoke instruction unwinds to the original catch end pad (which
- // is now the unwind destination of the cloned catch pad).
- auto *OrigInvoke = cast<InvokeInst>(OrigBlock->getTerminator());
- OrigInvoke->setUnwindDest(OrigCatch->getUnwindDest());
- } else {
- // If the invoke unwinds to a catch end pad that is not the unwind
- // destination for the original catch pad, it must be the unwind
- // destination for a sibling catch end pad. We'll handle that case
- // later.
- assert((getEndPadForCatch(OrigCatch) == UnwindDest ||
- getEndPadForCatch(CloneCatch) == UnwindDest) &&
- "Invoke within catch pad unwinds to an invalid catch end pad.");
- }
- }
- }
-}
-
-// Clones all blocks used by the specified funclet to avoid the funclet having
-// multiple parent funclets. All terminators in the parent that unwind to the
-// original funclet are remapped to unwind to the clone. Any terminator in the
-// original funclet which returned to this parent is converted to an unreachable
-// instruction. Likewise, any terminator in the cloned funclet which returns to
-// a parent funclet other than the specified parent is converted to an
-// unreachable instruction.
-BasicBlock *WinEHPrepare::cloneFuncletForParent(Function &F,
- BasicBlock *FuncletEntry,
- BasicBlock *Parent) {
- std::set<BasicBlock *> &BlocksInFunclet = FuncletBlocks[FuncletEntry];
-
- DEBUG_WITH_TYPE("winehprepare-coloring",
- dbgs() << "Cloning funclet \'" << FuncletEntry->getName()
- << "\' for parent \'" << Parent->getName() << "\'.\n");
-
- std::map<BasicBlock *, BasicBlock *> Orig2Clone;
- ValueToValueMapTy VMap;
- for (BasicBlock *BB : BlocksInFunclet) {
- // Create a new basic block and copy instructions into it.
- BasicBlock *CBB =
- CloneBasicBlock(BB, VMap, Twine(".from.", Parent->getName()));
-
- // Insert the clone immediately after the original to ensure determinism
- // and to keep the same relative ordering of any funclet's blocks.
- CBB->insertInto(&F, BB->getNextNode());
-
- // Add basic block mapping.
- VMap[BB] = CBB;
-
- // Record delta operations that we need to perform to our color mappings.
- Orig2Clone[BB] = CBB;
- } // end for (BasicBlock *BB : BlocksInFunclet)
-
- BasicBlock *ClonedFunclet = Orig2Clone[FuncletEntry];
- assert(ClonedFunclet);
-
- // Set the coloring for the blocks we just cloned.
- std::set<BasicBlock *> &ClonedBlocks = FuncletBlocks[ClonedFunclet];
- for (auto &BBMapping : Orig2Clone) {
- BasicBlock *NewBlock = BBMapping.second;
- ClonedBlocks.insert(NewBlock);
- BlockColors[NewBlock].insert(ClonedFunclet);
-
- DEBUG_WITH_TYPE("winehprepare-coloring",
- dbgs() << " Assigning color \'" << ClonedFunclet->getName()
- << "\' to block \'" << NewBlock->getName()
- << "\'.\n");
-
- // Use the VMap to remap the instructions in this cloned block.
- for (Instruction &I : *NewBlock)
- RemapInstruction(&I, VMap, RF_IgnoreMissingEntries);
- }
-
- // All the cloned blocks have to be colored in the loop above before we can
- // update the terminators because doing so can require checking the color of
- // other blocks in the cloned funclet.
- for (auto &BBMapping : Orig2Clone) {
- BasicBlock *OldBlock = BBMapping.first;
- BasicBlock *NewBlock = BBMapping.second;
-
- // Update the terminator, if necessary, in both the original block and the
- // cloned so that the original funclet never returns to a block in the
- // clone parent and the clone funclet never returns to a block in any other
- // of the original funclet's parents.
- updateTerminatorsAfterFuncletClone(F, FuncletEntry, ClonedFunclet, OldBlock,
- NewBlock, Parent, VMap, Orig2Clone);
-
- // Check to see if the cloned block successor has PHI nodes. If so, we need
- // to add entries to the PHI nodes for the cloned block now.
- for (BasicBlock *SuccBB : successors(NewBlock)) {
- for (Instruction &SuccI : *SuccBB) {
- auto *SuccPN = dyn_cast<PHINode>(&SuccI);
- if (!SuccPN)
- break;
-
- // Ok, we have a PHI node. Figure out what the incoming value was for
- // the OldBlock.
- int OldBlockIdx = SuccPN->getBasicBlockIndex(OldBlock);
- if (OldBlockIdx == -1)
- break;
- Value *IV = SuccPN->getIncomingValue(OldBlockIdx);
-
- // Remap the value if necessary.
- if (auto *Inst = dyn_cast<Instruction>(IV)) {
- ValueToValueMapTy::iterator I = VMap.find(Inst);
- if (I != VMap.end())
- IV = I->second;
- }
-
- SuccPN->addIncoming(IV, NewBlock);
- }
- }
- }
-
- // Erase the clone's parent from the original funclet's parent list.
- std::vector<BasicBlock *> &Parents = FuncletParents[FuncletEntry];
- Parents.erase(std::remove(Parents.begin(), Parents.end(), Parent),
- Parents.end());
-
- // Store the cloned funclet's parent.
- assert(std::find(FuncletParents[ClonedFunclet].begin(),
- FuncletParents[ClonedFunclet].end(),
- Parent) == std::end(FuncletParents[ClonedFunclet]));
- FuncletParents[ClonedFunclet].push_back(Parent);
-
- // Copy any children of the original funclet to the clone. We'll either
- // clone them too or make that path unreachable when we take the next step
- // in resolveFuncletAncestryForPath().
- for (auto *Child : FuncletChildren[FuncletEntry]) {
- assert(std::find(FuncletChildren[ClonedFunclet].begin(),
- FuncletChildren[ClonedFunclet].end(),
- Child) == std::end(FuncletChildren[ClonedFunclet]));
- FuncletChildren[ClonedFunclet].push_back(Child);
- assert(std::find(FuncletParents[Child].begin(), FuncletParents[Child].end(),
- ClonedFunclet) == std::end(FuncletParents[Child]));
- FuncletParents[Child].push_back(ClonedFunclet);
- }
-
- // Find any blocks that unwound to the original funclet entry from the
- // clone parent block and remap them to the clone.
- for (auto *U : FuncletEntry->users()) {
- auto *UT = dyn_cast<TerminatorInst>(U);
- if (!UT)
- continue;
- BasicBlock *UBB = UT->getParent();
- assert(BlockColors[UBB].size() == 1);
- BasicBlock *UFunclet = *(BlockColors[UBB].begin());
- // Funclets shouldn't be able to loop back on themselves.
- assert(UFunclet != FuncletEntry);
- // If this instruction unwinds to the original funclet from the clone
- // parent, remap the terminator so that it unwinds to the clone instead.
- // We will perform a similar transformation for siblings after all
- // the siblings have been cloned.
- if (UFunclet == Parent) {
- // We're about to break the path from this block to the uncloned funclet
- // entry, so remove it as a predeccessor to clean up the PHIs.
- FuncletEntry->removePredecessor(UBB);
- TerminatorInst *Terminator = UBB->getTerminator();
- RemapInstruction(Terminator, VMap, RF_IgnoreMissingEntries);
- }
- }
-
- // This asserts a condition that is relied upon inside the loop below,
- // namely that no predecessors of the original funclet entry block
- // are also predecessors of the cloned funclet entry block.
- assert(std::all_of(pred_begin(FuncletEntry), pred_end(FuncletEntry),
- [&ClonedFunclet](BasicBlock *Pred) {
- return std::find(pred_begin(ClonedFunclet),
- pred_end(ClonedFunclet),
- Pred) == pred_end(ClonedFunclet);
- }));
-
- // Remove any invalid PHI node entries in the cloned funclet.cl
- std::vector<PHINode *> PHIsToErase;
- for (Instruction &I : *ClonedFunclet) {
- auto *PN = dyn_cast<PHINode>(&I);
- if (!PN)
- break;
-
- // Predecessors of the original funclet do not reach the cloned funclet,
- // but the cloning process assumes they will. Remove them now.
- for (auto *Pred : predecessors(FuncletEntry))
- PN->removeIncomingValue(Pred, false);
- }
- for (auto *PN : PHIsToErase)
- PN->eraseFromParent();
-
- // Replace the original funclet in the parent's children vector with the
- // cloned funclet.
- for (auto &It : FuncletChildren[Parent]) {
- if (It == FuncletEntry) {
- It = ClonedFunclet;
- break;
- }
- }
-
- return ClonedFunclet;
-}
-
-// Removes the unwind edge for any exceptional terminators within the specified
-// parent funclet that previously unwound to the specified child funclet.
-void WinEHPrepare::makeFuncletEdgeUnreachable(BasicBlock *Parent,
- BasicBlock *Child) {
- for (BasicBlock *BB : FuncletBlocks[Parent]) {
- TerminatorInst *Terminator = BB->getTerminator();
- if (!Terminator->isExceptional())
- continue;
-
- // Look for terninators that unwind to the child funclet.
- BasicBlock *UnwindDest = nullptr;
- if (auto *I = dyn_cast<InvokeInst>(Terminator))
- UnwindDest = I->getUnwindDest();
- else if (auto *I = dyn_cast<CatchEndPadInst>(Terminator))
- UnwindDest = I->getUnwindDest();
- else if (auto *I = dyn_cast<TerminatePadInst>(Terminator))
- UnwindDest = I->getUnwindDest();
- // cleanupendpad, catchret and cleanupret don't represent a parent-to-child
- // funclet transition, so we don't need to consider them here.
-
- // If the child funclet is the unwind destination, replace the terminator
- // with an unreachable instruction.
- if (UnwindDest == Child)
- removeUnwindEdge(BB);
- }
- // The specified parent is no longer a parent of the specified child.
- std::vector<BasicBlock *> &Children = FuncletChildren[Parent];
- Children.erase(std::remove(Children.begin(), Children.end(), Child),
- Children.end());
-}
-
-// This routine is called after funclets with multiple parents are cloned for
-// a specific parent. Here we look for children of the specified funclet that
-// unwind to other children of that funclet and update the unwind destinations
-// to ensure that each sibling is connected to the correct clone of the sibling
-// to which it unwinds.
-static void updateSiblingToSiblingUnwind(
- BasicBlock *CurFunclet,
- std::map<BasicBlock *, std::set<BasicBlock *>> &BlockColors,
- std::map<BasicBlock *, std::set<BasicBlock *>> &FuncletBlocks,
- std::map<BasicBlock *, std::vector<BasicBlock *>> &FuncletParents,
- std::map<BasicBlock *, std::vector<BasicBlock *>> &FuncletChildren,
- std::map<BasicBlock *, BasicBlock *> &Funclet2Orig) {
- // Remap any bad sibling-to-sibling transitions for funclets that
- // we just cloned.
- for (BasicBlock *ChildFunclet : FuncletChildren[CurFunclet]) {
- bool NeedOrigInvokeRemapping = false;
- for (auto *BB : FuncletBlocks[ChildFunclet]) {
- TerminatorInst *Terminator = BB->getTerminator();
- if (!Terminator->isExceptional())
- continue;
-
- // See if this terminator has an unwind destination.
- // Note that catchendpads are handled when the associated catchpad
- // is cloned. They don't fit the pattern we're looking for here.
- BasicBlock *UnwindDest = nullptr;
- if (auto *II = dyn_cast<InvokeInst>(Terminator)) {
- UnwindDest = II->getUnwindDest();
- assert(UnwindDest && "Invoke unwinds to a null destination.");
- assert(UnwindDest->isEHPad() && "Invoke does not unwind to an EH pad.");
- auto *EHPadInst = UnwindDest->getFirstNonPHI();
- if (isa<CatchEndPadInst>(EHPadInst)) {
- // If the invoke unwind destination is the unwind destination for
- // the current child catch pad funclet, there is nothing to be done.
- auto *CurCatch = cast<CatchPadInst>(ChildFunclet->getFirstNonPHI());
- if (CurCatch->getUnwindDest() == UnwindDest)
- continue;
-
- // Otherwise, the invoke unwinds to a catch end pad that is the unwind
- // destination another catch pad in the unwind chain from either the
- // current catch pad or one of its clones. If it is already the
- // catch end pad at the end unwind chain from the current catch pad,
- // we'll need to check the invoke instructions in the original funclet
- // later. Otherwise, we need to remap this invoke now.
- BasicBlock *CurCatchEnd = getEndPadForCatch(CurCatch);
- if (CurCatchEnd == UnwindDest)
- NeedOrigInvokeRemapping = true;
- else
- II->setUnwindDest(CurCatchEnd);
- continue;
- }
- // All other unwind scenarios for the invoke are handled elsewhere.
- continue;
- } else if (auto *I = dyn_cast<CatchPadInst>(Terminator)) {
- UnwindDest = I->getUnwindDest();
- // The catchendpad is not a sibling destination. This case should
- // have been handled in cloneFuncletForParent().
- if (isa<CatchEndPadInst>(Terminator)) {
- assert(BlockColors[UnwindDest].size() == 1 &&
- "Cloned catchpad unwinds to an pad with multiple parents.");
- assert(FuncletParents[UnwindDest].front() == CurFunclet &&
- "Cloned catchpad unwinds to the wrong parent.");
- continue;
- }
- } else {
- if (auto *I = dyn_cast<CleanupReturnInst>(Terminator))
- UnwindDest = I->getUnwindDest();
- else if (auto *I = dyn_cast<CleanupEndPadInst>(Terminator))
- UnwindDest = I->getUnwindDest();
-
- // If the cleanup unwinds to caller, there is nothing to be done.
- if (!UnwindDest)
- continue;
- }
-
- // If the destination is not a cleanup pad, catch pad or terminate pad
- // we don't need to handle it here.
- Instruction *EHPad = UnwindDest->getFirstNonPHI();
- if (!isa<CleanupPadInst>(EHPad) && !isa<CatchPadInst>(EHPad) &&
- !isa<TerminatePadInst>(EHPad))
- continue;
-
- // If it is one of these, then it is either a sibling of the current
- // child funclet or a clone of one of those siblings.
- // If it is a sibling, no action is needed.
- if (FuncletParents[UnwindDest].size() == 1 &&
- FuncletParents[UnwindDest].front() == CurFunclet)
- continue;
-
- // If the unwind destination is a clone of a sibling, we need to figure
- // out which sibling it is a clone of and use that sibling as the
- // unwind destination.
- BasicBlock *DestOrig = Funclet2Orig[UnwindDest];
- BasicBlock *TargetSibling = nullptr;
- for (auto &Mapping : Funclet2Orig) {
- if (Mapping.second != DestOrig)
- continue;
- BasicBlock *MappedFunclet = Mapping.first;
- if (FuncletParents[MappedFunclet].size() == 1 &&
- FuncletParents[MappedFunclet].front() == CurFunclet) {
- TargetSibling = MappedFunclet;
- }
- }
- // If we didn't find the sibling we were looking for then the
- // unwind destination is not a clone of one of child's siblings.
- // That's unexpected.
- assert(TargetSibling && "Funclet unwinds to unexpected destination.");
-
- // Update the terminator instruction to unwind to the correct sibling.
- if (auto *I = dyn_cast<CatchPadInst>(Terminator))
- I->setUnwindDest(TargetSibling);
- else if (auto *I = dyn_cast<CleanupReturnInst>(Terminator))
- I->setUnwindDest(TargetSibling);
- else if (auto *I = dyn_cast<CleanupEndPadInst>(Terminator))
- I->setUnwindDest(TargetSibling);
- }
- if (NeedOrigInvokeRemapping) {
- // To properly remap invoke instructions that unwind to catch end pads
- // that are not the unwind destination of the catch pad funclet in which
- // the invoke appears, we must also look at the uncloned invoke in the
- // original funclet. If we saw an invoke that was already properly
- // unwinding to a sibling's catch end pad, we need to check the invokes
- // in the original funclet.
- BasicBlock *OrigFunclet = Funclet2Orig[ChildFunclet];
- for (auto *BB : FuncletBlocks[OrigFunclet]) {
- auto *II = dyn_cast<InvokeInst>(BB->getTerminator());
- if (!II)
- continue;
-
- BasicBlock *UnwindDest = II->getUnwindDest();
- assert(UnwindDest && "Invoke unwinds to a null destination.");
- assert(UnwindDest->isEHPad() && "Invoke does not unwind to an EH pad.");
- auto *CEP = dyn_cast<CatchEndPadInst>(UnwindDest->getFirstNonPHI());
- if (!CEP)
- continue;
- // If the invoke unwind destination is the unwind destination for
- // the original catch pad funclet, there is nothing to be done.
- auto *OrigCatch = cast<CatchPadInst>(OrigFunclet->getFirstNonPHI());
- if (OrigCatch->getUnwindDest() == UnwindDest)
- continue;
-
- // Otherwise, the invoke unwinds to a catch end pad that is the unwind
- // destination another catch pad in the unwind chain from either the
- // current catch pad or one of its clones. If it is not already the
- // catch end pad at the end unwind chain from the current catch pad,
- // we need to remap this invoke now.
- BasicBlock *OrigCatchEnd = getEndPadForCatch(OrigCatch);
- if (OrigCatchEnd != UnwindDest)
- II->setUnwindDest(OrigCatchEnd);
- }
- }
- }
-}
-
-void WinEHPrepare::resolveFuncletAncestry(
- Function &F, SmallVectorImpl<BasicBlock *> &EntryBlocks) {
- // Most of the time this will be unnecessary. If the conditions arise that
- // require this work, this flag will be set.
- if (!FuncletCloningRequired)
- return;
-
- // Funclet2Orig is used to map any cloned funclets back to the original
- // funclet from which they were cloned. The map is seeded with the
- // original funclets mapping to themselves.
- std::map<BasicBlock *, BasicBlock *> Funclet2Orig;
- for (auto *Funclet : EntryBlocks)
- Funclet2Orig[Funclet] = Funclet;
-
- // Start with the entry funclet and walk the funclet parent-child tree.
- SmallVector<BasicBlock *, 4> FuncletPath;
- FuncletPath.push_back(&(F.getEntryBlock()));
- resolveFuncletAncestryForPath(F, FuncletPath, Funclet2Orig);
-}
-
-// Walks the funclet control flow, cloning any funclets that have more than one
-// parent funclet and breaking any cyclic unwind chains so that the path becomes
-// unreachable at the point where a funclet would have unwound to a funclet that
-// was already in the chain.
-void WinEHPrepare::resolveFuncletAncestryForPath(
- Function &F, SmallVectorImpl<BasicBlock *> &FuncletPath,
- std::map<BasicBlock *, BasicBlock *> &Funclet2Orig) {
- bool ClonedAnyChildren = false;
- BasicBlock *CurFunclet = FuncletPath.back();
- // Copy the children vector because we might changing it.
- std::vector<BasicBlock *> Children(FuncletChildren[CurFunclet]);
- for (BasicBlock *ChildFunclet : Children) {
- // Don't allow the funclet chain to unwind back on itself.
- // If this funclet is already in the current funclet chain, make the
- // path to it through the current funclet unreachable.
- bool IsCyclic = false;
- BasicBlock *ChildIdentity = Funclet2Orig[ChildFunclet];
- for (BasicBlock *Ancestor : FuncletPath) {
- BasicBlock *AncestorIdentity = Funclet2Orig[Ancestor];
- if (AncestorIdentity == ChildIdentity) {
- IsCyclic = true;
- break;
- }
- }
- // If the unwind chain wraps back on itself, break the chain.
- if (IsCyclic) {
- makeFuncletEdgeUnreachable(CurFunclet, ChildFunclet);
- continue;
- }
- // If this child funclet has other parents, clone the entire funclet.
- if (FuncletParents[ChildFunclet].size() > 1) {
- ChildFunclet = cloneFuncletForParent(F, ChildFunclet, CurFunclet);
- Funclet2Orig[ChildFunclet] = ChildIdentity;
- ClonedAnyChildren = true;
- }
- FuncletPath.push_back(ChildFunclet);
- resolveFuncletAncestryForPath(F, FuncletPath, Funclet2Orig);
- FuncletPath.pop_back();
- }
- // If we didn't clone any children, we can return now.
- if (!ClonedAnyChildren)
- return;
-
- updateSiblingToSiblingUnwind(CurFunclet, BlockColors, FuncletBlocks,
- FuncletParents, FuncletChildren, Funclet2Orig);
-}
-
-void WinEHPrepare::colorFunclets(Function &F,
- SmallVectorImpl<BasicBlock *> &EntryBlocks) {
- ::colorFunclets(F, EntryBlocks, BlockColors, FuncletBlocks);
// The processing above actually accumulated the parent set for this
// funclet into the color set for its entry; use the parent set to
@@ -1496,27 +657,18 @@ void WinEHPrepare::colorFunclets(Functio
// that transitions to the child funclet).
for (BasicBlock *FuncletEntry : EntryBlocks) {
std::set<BasicBlock *> &ColorMapItem = BlockColors[FuncletEntry];
- // It will be rare for funclets to have multiple parents, but if any
- // do we need to clone the funclet later to address that. Here we
- // set a flag indicating that this case has arisen so that we don't
- // have to do a lot of checking later to handle the more common case.
- if (ColorMapItem.size() > 1)
- FuncletCloningRequired = true;
- for (BasicBlock *Parent : ColorMapItem) {
- assert(std::find(FuncletChildren[Parent].begin(),
- FuncletChildren[Parent].end(),
- FuncletEntry) == std::end(FuncletChildren[Parent]));
- FuncletChildren[Parent].push_back(FuncletEntry);
- assert(std::find(FuncletParents[FuncletEntry].begin(),
- FuncletParents[FuncletEntry].end(),
- Parent) == std::end(FuncletParents[FuncletEntry]));
- FuncletParents[FuncletEntry].push_back(Parent);
- }
+ for (BasicBlock *Parent : ColorMapItem)
+ FuncletChildren[Parent].insert(FuncletEntry);
ColorMapItem.clear();
ColorMapItem.insert(FuncletEntry);
}
}
+void WinEHPrepare::colorFunclets(Function &F,
+ SmallVectorImpl<BasicBlock *> &EntryBlocks) {
+ ::colorFunclets(F, EntryBlocks, BlockColors, FuncletBlocks, FuncletChildren);
+}
+
void llvm::calculateCatchReturnSuccessorColors(const Function *Fn,
WinEHFuncInfo &FuncInfo) {
SmallVector<BasicBlock *, 4> EntryBlocks;
@@ -1526,18 +678,10 @@ void llvm::calculateCatchReturnSuccessor
std::map<BasicBlock *, std::set<BasicBlock *>> BlockColors;
std::map<BasicBlock *, std::set<BasicBlock *>> FuncletBlocks;
+ std::map<BasicBlock *, std::set<BasicBlock *>> FuncletChildren;
// Figure out which basic blocks belong to which funclets.
colorFunclets(const_cast<Function &>(*Fn), EntryBlocks, BlockColors,
- FuncletBlocks);
-
- // The static colorFunclets routine assigns multiple colors to funclet entries
- // because that information is needed to calculate funclets' parent-child
- // relationship, but we don't need those relationship here and ultimately the
- // entry blocks should have the color of the funclet they begin.
- for (BasicBlock *FuncletEntry : EntryBlocks) {
- BlockColors[FuncletEntry].clear();
- BlockColors[FuncletEntry].insert(FuncletEntry);
- }
+ FuncletBlocks, FuncletChildren);
// We need to find the catchret successors. To do this, we must first find
// all the catchpad funclets.
@@ -1628,71 +772,13 @@ void WinEHPrepare::cloneCommonBlocks(
std::map<BasicBlock *, BasicBlock *> Orig2Clone;
ValueToValueMapTy VMap;
- for (auto BlockIt = BlocksInFunclet.begin(),
- BlockEnd = BlocksInFunclet.end();
- BlockIt != BlockEnd;) {
- // Increment the iterator inside the loop because we might be removing
- // blocks from the set.
- BasicBlock *BB = *BlockIt++;
+ for (BasicBlock *BB : BlocksInFunclet) {
std::set<BasicBlock *> &ColorsForBB = BlockColors[BB];
// We don't need to do anything if the block is monochromatic.
size_t NumColorsForBB = ColorsForBB.size();
if (NumColorsForBB == 1)
continue;
- // If this block is a catchendpad, it shouldn't be cloned.
- // We will only see a catchendpad with multiple colors in the case where
- // some funclet has multiple parents. In that case, the color will be
- // resolved during the resolveFuncletAncestry processing.
- // For now, find the catchpad that unwinds to this block and assign
- // that catchpad's first parent to be the color for this block.
- if (isa<CatchEndPadInst>(BB->getFirstNonPHI())) {
- assert(
- FuncletCloningRequired &&
- "Found multi-colored catchendpad with no multi-parent funclets.");
- BasicBlock *CatchParent = nullptr;
- // There can only be one catchpad predecessor for a catchendpad.
- for (BasicBlock *PredBB : predecessors(BB)) {
- if (isa<CatchPadInst>(PredBB->getTerminator())) {
- CatchParent = PredBB;
- break;
- }
- }
- // There must be one catchpad predecessor for a catchendpad.
- assert(CatchParent && "No catchpad found for catchendpad.");
-
- // If the catchpad has multiple parents, we'll clone the catchendpad
- // when we clone the catchpad funclet and insert it into the correct
- // funclet. For now, we just select the first parent of the catchpad
- // and give the catchendpad that color.
- BasicBlock *CorrectColor = FuncletParents[CatchParent].front();
- assert(FuncletBlocks[CorrectColor].count(BB));
- assert(BlockColors[BB].count(CorrectColor));
-
- // Remove this block from the FuncletBlocks set of any funclet that
- // isn't the funclet whose color we just selected.
- for (auto It = BlockColors[BB].begin(), End = BlockColors[BB].end();
- It != End; ) {
- // The iterator must be incremented here because we are removing
- // elements from the set we're walking.
- auto Temp = It++;
- BasicBlock *ContainingFunclet = *Temp;
- if (ContainingFunclet != CorrectColor) {
- FuncletBlocks[ContainingFunclet].erase(BB);
- BlockColors[BB].erase(Temp);
- }
- }
-
- // This should leave just one color for BB.
- assert(BlockColors[BB].size() == 1);
- continue;
- }
-
- DEBUG_WITH_TYPE("winehprepare-coloring",
- dbgs() << " Cloning block \'" << BB->getName()
- << "\' for funclet \'" << FuncletPadBB->getName()
- << "\'.\n");
-
// Create a new basic block and copy instructions into it!
BasicBlock *CBB =
CloneBasicBlock(BB, VMap, Twine(".for.", FuncletPadBB->getName()));
@@ -1720,52 +806,8 @@ void WinEHPrepare::cloneCommonBlocks(
BlocksInFunclet.insert(NewBlock);
BlockColors[NewBlock].insert(FuncletPadBB);
- DEBUG_WITH_TYPE("winehprepare-coloring",
- dbgs() << " Assigned color \'" << FuncletPadBB->getName()
- << "\' to block \'" << NewBlock->getName()
- << "\'.\n");
-
BlocksInFunclet.erase(OldBlock);
BlockColors[OldBlock].erase(FuncletPadBB);
-
- DEBUG_WITH_TYPE("winehprepare-coloring",
- dbgs() << " Removed color \'" << FuncletPadBB->getName()
- << "\' from block \'" << OldBlock->getName()
- << "\'.\n");
-
- // If we are cloning a funclet that might share a child funclet with
- // another funclet, look to see if the cloned block is reached from a
- // catchret instruction. If so, save this association so we can retrieve
- // the possibly orphaned clone when we clone the child funclet.
- if (FuncletCloningRequired) {
- for (auto *Pred : predecessors(OldBlock)) {
- auto *Terminator = Pred->getTerminator();
- if (!isa<CatchReturnInst>(Terminator))
- continue;
- // If this block is reached from a catchret instruction in a funclet
- // that has multiple parents, it will have a color for each of those
- // parents. We just removed the color of one of the parents, but
- // the cloned block will be unreachable until we clone the child
- // funclet that contains the catchret instruction. In that case we
- // need to create a mapping that will let us find the cloned block
- // later and associate it with the cloned child funclet.
- bool BlockWillBeEstranged = false;
- for (auto *Color : BlockColors[Pred]) {
- if (FuncletParents[Color].size() > 1) {
- BlockWillBeEstranged = true;
- break; // Breaks out of the color loop
- }
- }
- if (BlockWillBeEstranged) {
- EstrangedBlocks[FuncletPadBB][OldBlock] = NewBlock;
- DEBUG_WITH_TYPE("winehprepare-coloring",
- dbgs() << " Saved mapping of estranged block \'"
- << NewBlock->getName() << "\' for \'"
- << FuncletPadBB->getName() << "\'.\n");
- break; // Breaks out of the predecessor loop
- }
- }
- }
}
// Loop over all of the instructions in this funclet, fixing up operand
@@ -1952,8 +994,6 @@ bool WinEHPrepare::prepareExplicitEH(
cloneCommonBlocks(F, EntryBlocks);
- resolveFuncletAncestry(F, EntryBlocks);
-
if (!DisableCleanups) {
removeImplausibleTerminators(F);
@@ -1965,9 +1005,6 @@ bool WinEHPrepare::prepareExplicitEH(
BlockColors.clear();
FuncletBlocks.clear();
FuncletChildren.clear();
- FuncletParents.clear();
- EstrangedBlocks.clear();
- FuncletCloningRequired = false;
return true;
}
Modified: llvm/trunk/test/CodeGen/WinEH/wineh-cloning.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WinEH/wineh-cloning.ll?rev=252279&r1=252278&r2=252279&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WinEH/wineh-cloning.ll (original)
+++ llvm/trunk/test/CodeGen/WinEH/wineh-cloning.ll Fri Nov 6 04:07:33 2015
@@ -280,30 +280,7 @@ exit:
; the dynamic path enters %left, then enters %inner,
; then calls @h, and that the call to @h doesn't return.
; CHECK-LABEL: define void @test6(
-; CHECK: left:
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: to label %right.catch unwind label %right.end
-; CHECK: right.catch:
-; CHECK: %x = call i32 @g()
-; CHECK: store i32 %x, i32* %x.wineh.spillslot
-; CHECK: to label %shared.cont unwind label %[[INNER_RIGHT:.+]]
-; CHECK: right.end:
-; CHECK: catchendpad unwind to caller
-; CHECK: shared.cont:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: [[I_R:\%.+]] = cleanuppad []
-; CHECK: [[X_RELOAD_R:\%.+]] = load i32, i32* %x.wineh.spillslot
-; CHECK: call void @h(i32 [[X_RELOAD_R]])
-; CHECK: cleanupret [[I_R]] unwind label %right.end
-; CHECK: [[INNER_LEFT]]:
-; CHECK: [[I_L:\%.+]] = cleanuppad []
-; CHECK: [[X_RELOAD_L:\%.+]] = load i32, i32* %x.wineh.spillslot
-; CHECK: call void @h(i32 [[X_RELOAD_L]])
-; CHECK: unreachable
+; TODO: CHECKs
define void @test7() personality i32 (...)* @__CxxFrameHandler3 {
@@ -335,32 +312,7 @@ unreachable:
; with the join at the entry itself instead of following a
; non-pad join.
; CHECK-LABEL: define void @test7(
-; CHECK: invoke.cont:
-; CHECK: to label %[[UNREACHABLE_ENTRY:.+]] unwind label %right
-; CHECK: left:
-; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: to label %right.catch unwind label %right.end
-; CHECK: right.catch:
-; CHECK: to label %unreachable unwind label %[[INNER_RIGHT:.+]]
-; CHECK: right.end:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: [[I_R:\%.+]] = cleanuppad []
-; CHECK: [[X_R:\%.+]] = call i32 @g()
-; CHECK: call void @h(i32 [[X_R]])
-; CHECK: cleanupret [[I_R]] unwind label %right.end
-; CHECK: [[INNER_LEFT]]:
-; CHECK: [[I_L:\%.+]] = cleanuppad []
-; CHECK: [[X_L:\%.+]] = call i32 @g()
-; CHECK: call void @h(i32 [[X_L]])
-; CHECK: unreachable
-; CHECK: unreachable:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_ENTRY]]:
-; CHECK: unreachable
+; TODO: CHECKs
define void @test8() personality i32 (...)* @__CxxFrameHandler3 {
@@ -398,40 +350,7 @@ unreachable:
; %inner is a two-parent child which itself has a child; need
; to make two copies of both the %inner and %inner.child.
; CHECK-LABEL: define void @test8(
-; CHECK: invoke.cont:
-; CHECK: to label %[[UNREACHABLE_ENTRY:.+]] unwind label %right
-; CHECK: left:
-; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: to label %right.catch unwind label %right.end
-; CHECK: right.catch:
-; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: right.end:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: to label %[[UNREACHABLE_INNER_RIGHT:.+]] unwind label %[[INNER_CHILD_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: to label %[[UNREACHABLE_INNER_LEFT:.+]] unwind label %[[INNER_CHILD_LEFT:.+]]
-; CHECK: [[INNER_CHILD_RIGHT]]:
-; CHECK: [[TMP:\%.+]] = cleanuppad []
-; CHECK: [[X:\%.+]] = call i32 @g()
-; CHECK: call void @h(i32 [[X]])
-; CHECK: unreachable
-; CHECK: [[INNER_CHILD_LEFT]]:
-; CHECK: [[TMP:\%.+]] = cleanuppad []
-; CHECK: [[X:\%.+]] = call i32 @g()
-; CHECK: call void @h(i32 [[X]])
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_INNER_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_INNER_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_ENTRY]]:
-; CHECK: unreachable
+; TODO: CHECKs
define void @test9() personality i32 (...)* @__CxxFrameHandler3 {
@@ -464,33 +383,7 @@ unreachable:
; of which was which along the way; generating each possibility lets
; whichever case was correct execute correctly.
; CHECK-LABEL: define void @test9(
-; CHECK: entry:
-; CHECK: to label %invoke.cont unwind label %[[LEFT:.+]]
-; CHECK: invoke.cont:
-; CHECK: to label %[[UNREACHABLE_ENTRY:.+]] unwind label %[[RIGHT:.+]]
-; CHECK: [[LEFT_FROM_RIGHT:.+]]:
-; CHECK: call void @h(i32 1)
-; CHECK: call void @f()
-; CHECK: unreachable
-; CHECK: [[LEFT]]:
-; CHECK: call void @h(i32 1)
-; CHECK: invoke void @f()
-; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[RIGHT_FROM_LEFT:.+]]
-; CHECK: [[RIGHT]]:
-; CHECK: call void @h(i32 2)
-; CHECK: invoke void @f()
-; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[LEFT_FROM_RIGHT]]
-; CHECK: [[RIGHT_FROM_LEFT]]:
-; CHECK: call void @h(i32 2)
-; CHECK: call void @f()
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_ENTRY]]:
-; CHECK: unreachable
-
+; TODO: CHECKs
define void @test10() personality i32 (...)* @__CxxFrameHandler3 {
entry:
Modified: llvm/trunk/test/CodeGen/WinEH/wineh-demotion.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WinEH/wineh-demotion.ll?rev=252279&r1=252278&r2=252279&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WinEH/wineh-demotion.ll (original)
+++ llvm/trunk/test/CodeGen/WinEH/wineh-demotion.ll Fri Nov 6 04:07:33 2015
@@ -86,18 +86,18 @@ catch.inner:
; CHECK: store i32 %z
; CHECK-NEXT: invoke void @f
invoke void @f()
- to label %catchret.inner unwind label %catchend.inner
+ to label %catchret.inner unwind label %merge.outer
catchret.inner:
catchret %cpinner to label %exit
catchend.inner:
- ; CHECK-NOT: = phi
- %y = phi i32 [ %x, %merge.inner ], [ %z, %catch.inner ]
catchendpad unwind label %merge.outer
merge.outer:
; CHECK: merge.outer:
+ ; CHECK-NOT: = phi
; CHECK: [[CatchPad:%[^ ]+]] = catchpad []
+ %y = phi i32 [ %x, %catchend.inner ], [ %z, %catch.inner ]
%cpouter = catchpad [] to label %catch.outer unwind label %catchend.outer
catchend.outer:
Removed: llvm/trunk/test/CodeGen/WinEH/wineh-multi-parent-cloning.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WinEH/wineh-multi-parent-cloning.ll?rev=252278&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/WinEH/wineh-multi-parent-cloning.ll (original)
+++ llvm/trunk/test/CodeGen/WinEH/wineh-multi-parent-cloning.ll (removed)
@@ -1,1561 +0,0 @@
-; RUN: opt -mtriple=x86_x64-pc-windows-msvc -S -winehprepare < %s | FileCheck %s
-
-declare i32 @__CxxFrameHandler3(...)
-
-declare void @f()
-declare i32 @g()
-declare void @h(i32)
-declare i1 @b()
-
-define void @test1() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %invoke.cont unwind label %left
-invoke.cont:
- invoke void @f()
- to label %exit unwind label %right
-left:
- cleanuppad []
- br label %shared
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- %x = call i32 @g()
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- %i = cleanuppad []
- call void @h(i32 %x)
- cleanupret %i unwind label %right.end
-exit:
- ret void
-}
-; %inner is a cleanup which appears both as a child of
-; %left and as a child of %right. Since statically we
-; need each funclet to have a single parent, we need to
-; clone the entire %inner funclet so we can have one
-; copy under each parent. The cleanupret in %inner
-; unwinds to the catchendpad for %right, so the copy
-; of %inner under %right should include it; the copy
-; of %inner under %left should instead have an
-; `unreachable` inserted there, but the copy under
-; %left still needs to be created because it's possible
-; the dynamic path enters %left, then enters %inner,
-; then calls @h, and that the call to @h doesn't return.
-; CHECK-LABEL: define void @test1(
-; CHECK: left:
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: to label %right.catch unwind label %right.end
-; CHECK: right.catch:
-; CHECK: %x = call i32 @g()
-; CHECK: store i32 %x, i32* %x.wineh.spillslot
-; CHECK: to label %shared.cont unwind label %[[INNER_RIGHT:.+]]
-; CHECK: right.end:
-; CHECK: catchendpad unwind to caller
-; CHECK: shared.cont:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: [[I_R:\%.+]] = cleanuppad []
-; CHECK: [[X_RELOAD_R:\%.+]] = load i32, i32* %x.wineh.spillslot
-; CHECK: call void @h(i32 [[X_RELOAD_R]])
-; CHECK: cleanupret [[I_R]] unwind label %right.end
-; CHECK: [[INNER_LEFT]]:
-; CHECK: [[I_L:\%.+]] = cleanuppad []
-; CHECK: [[X_RELOAD_L:\%.+]] = load i32, i32* %x.wineh.spillslot
-; CHECK: call void @h(i32 [[X_RELOAD_L]])
-; CHECK: unreachable
-
-
-define void @test2() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %invoke.cont unwind label %left
-invoke.cont:
- invoke void @f()
- to label %exit unwind label %right
-left:
- cleanuppad []
- br label %shared
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- %x = call i32 @g()
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 %x)
- unreachable
-inner.end:
- catchendpad unwind label %right.end
-exit:
- ret void
-}
-; In this case left and right are both parents of inner. This differs from
-; @test1 in that inner is a catchpad rather than a cleanuppad, which makes
-; inner.end a block that gets cloned so that left and right each contain a
-; copy (catchendpad blocks are considered to be part of the parent funclet
-; of the associated catchpad). The catchendpad in %inner.end unwinds to
-; %right.end (which belongs to the entry funclet).
-; CHECK-LABEL: define void @test2(
-; CHECK: left:
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: to label %right.catch unwind label %[[RIGHT_END:.+]]
-; CHECK: right.catch:
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: [[X_RELOAD_R:\%.+]] = load i32, i32* %x.wineh.spillslot
-; CHECK: call void @h(i32 [[X_RELOAD_R]])
-; CHECK: unreachable
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: [[X_RELOAD_L:\%.+]] = load i32, i32* %x.wineh.spillslot
-; CHECK: call void @h(i32 [[X_RELOAD_L]])
-; CHECK: unreachable
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind label %[[RIGHT_END]]
-
-define void @test3() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %exit unwind label %left
-left:
- %l = cleanuppad []
- br label %shared
-left.end:
- cleanupendpad %l unwind label %right
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- %x = call i32 @g()
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 %x)
- unreachable
-inner.end:
- catchendpad unwind label %left.end
-exit:
- ret void
-}
-; In this case, %left and %right are siblings with %entry as the parent of both,
-; while %left and %right are both parents of %inner. The catchendpad in
-; %inner.end unwinds to %left.end. When %inner is cloned a copy of %inner.end
-; will be made for both %left and %right, but because %left.end is a cleanup pad
-; and %right is a catch pad the unwind edge from the copy of %inner.end for
-; %right must be removed.
-; CHECK-LABEL: define void @test3(
-; CHECK: left:
-; CHECK: %l = cleanuppad []
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: [[LEFT_END:left.end.*]]:
-; CHECK: cleanupendpad %l unwind label %right
-; CHECK: right:
-; CHECK: to label %right.catch unwind label %[[RIGHT_END:.+]]
-; CHECK: right.catch:
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: [[X_RELOAD_R:\%.+]] = load i32, i32* %x.wineh.spillslot
-; CHECK: call void @h(i32 [[X_RELOAD_R]])
-; CHECK: unreachable
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: [[X_RELOAD_R:\%.+]] = load i32, i32* %x.wineh.spillslot
-; CHECK: call void @h(i32 [[X_RELOAD_R]])
-; CHECK: unreachable
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind label %[[LEFT_END]]
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind to caller
-
-
-define void @test4() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %exit unwind label %left
-left:
- catchpad []
- to label %left.catch unwind label %left.end
-left.catch:
- br label %shared
-left.end:
- catchendpad unwind label %right
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- %x = call i32 @g()
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 %x)
- unreachable
-inner.end:
- catchendpad unwind label %left.end
-exit:
- ret void
-}
-; This is a variation of @test3 in which both %left and %right are catch pads.
-; In this case, %left and %right are siblings with %entry as the parent of both,
-; while %left and %right are both parents of %inner. The catchendpad in
-; %inner.end unwinds to %left.end. When %inner is cloned a copy of %inner.end
-; will be made for both %left and %right, but because the catchpad in %right
-; does not unwind to %left.end the unwind edge from the copy of %inner.end for
-; %right must be removed.
-; CHECK-LABEL: define void @test4(
-; CHECK: left:
-; CHECK: catchpad []
-; CHECK: to label %left.catch unwind label %[[LEFT_END:.+]]
-; CHECK: left.catch:
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: [[LEFT_END]]:
-; CHECK: catchendpad unwind label %right
-; CHECK: right:
-; CHECK: to label %right.catch unwind label %[[RIGHT_END:.+]]
-; CHECK: right.catch:
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: [[X_RELOAD_R:\%.+]] = load i32, i32* %x.wineh.spillslot
-; CHECK: call void @h(i32 [[X_RELOAD_R]])
-; CHECK: unreachable
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: [[X_RELOAD_L:\%.+]] = load i32, i32* %x.wineh.spillslot
-; CHECK: call void @h(i32 [[X_RELOAD_L]])
-; CHECK: unreachable
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind label %[[LEFT_END]]
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind to caller
-
-
-define void @test5() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %exit unwind label %left
-left:
- catchpad []
- to label %left.catch unwind label %left.end
-left.catch:
- br label %shared
-left.end:
- catchendpad unwind label %right
-right:
- %r = cleanuppad []
- br label %shared
-shared:
- %x = call i32 @g()
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 %x)
- unreachable
-inner.end:
- catchendpad unwind label %left.end
-exit:
- ret void
-}
-; Like @test3, %left and %right are siblings with %entry as the parent of both,
-; while %left and %right are both parents of %inner. This case makes %left a
-; catch and %right a cleanup so that %inner unwinds to %left.end, which is a
-; block in %entry. The %inner funclet is cloned for %left and %right, but the
-; copy of %inner.end for %right must have its unwind edge removed because the
-; catchendpad at %left.end is not compatible with %right.
-; CHECK-LABEL: define void @test5(
-; CHECK: left:
-; CHECK: catchpad []
-; CHECK: to label %left.catch unwind label %[[LEFT_END:.+]]
-; CHECK: left.catch:
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: [[LEFT_END]]:
-; CHECK: catchendpad unwind label %right
-; CHECK: right:
-; CHECK: %r = cleanuppad []
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: [[X_RELOAD_R:\%.+]] = load i32, i32* %x.wineh.spillslot
-; CHECK: call void @h(i32 [[X_RELOAD_R]])
-; CHECK: unreachable
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: [[X_RELOAD_L:\%.+]] = load i32, i32* %x.wineh.spillslot
-; CHECK: call void @h(i32 [[X_RELOAD_L]])
-; CHECK: unreachable
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind label %[[LEFT_END]]
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind to caller
-
-define void @test6() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %exit unwind label %left
-left:
- catchpad []
- to label %left.catch unwind label %left.end
-left.catch:
- br label %shared
-left.end:
- catchendpad unwind label %middle
-middle:
- %m = catchpad []
- to label %middle.catch unwind label %middle.end
-middle.catch:
- catchret %m to label %exit
-middle.end:
- catchendpad unwind label %right
-right:
- %r = cleanuppad []
- br label %shared
-shared:
- %x = call i32 @g()
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 %x)
- unreachable
-inner.end:
- catchendpad unwind label %left.end
-exit:
- ret void
-}
-; This is like @test5 but it inserts another sibling between %left and %right.
-; In this case %left, %middle and %right are all siblings, while %left and
-; %right are both parents of %inner. This checks the proper handling of the
-; catchendpad in %inner.end (which will be cloned so that %left and %right both
-; have copies) unwinding to a catchendpad that unwinds to a sibling.
-; CHECK-LABEL: define void @test6(
-; CHECK: left:
-; CHECK: catchpad []
-; CHECK: to label %left.catch unwind label %[[LEFT_END:.+]]
-; CHECK: left.catch:
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: [[LEFT_END]]:
-; CHECK: catchendpad unwind label %middle
-; CHECK: middle:
-; CHECK: catchpad []
-; CHECK: to label %middle.catch unwind label %middle.end
-; CHECK: middle.catch:
-; CHECK: catchret %m to label %exit
-; CHECK: middle.end:
-; CHECK: catchendpad unwind label %right
-; CHECK: right:
-; CHECK: %r = cleanuppad []
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: [[X_RELOAD_R:\%.+]] = load i32, i32* %x.wineh.spillslot
-; CHECK: call void @h(i32 [[X_RELOAD_R]])
-; CHECK: unreachable
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: [[X_RELOAD_L:\%.+]] = load i32, i32* %x.wineh.spillslot
-; CHECK: call void @h(i32 [[X_RELOAD_L]])
-; CHECK: unreachable
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind label %[[LEFT_END]]
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind to caller
-
-
-define void @test7() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %exit unwind label %left
-left:
- catchpad []
- to label %left.catch unwind label %left.end
-left.catch:
- br label %shared
-left.end:
- catchendpad unwind label %right
-right:
- %r = cleanuppad []
- br label %shared
-shared:
- %x = call i32 @g()
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 %x)
- unreachable
-inner.end:
- catchendpad unwind label %inner.sibling
-inner.sibling:
- %is = cleanuppad []
- call void @h(i32 0)
- cleanupret %is unwind label %left.end
-exit:
- ret void
-}
-; This is like @test5 but instead of unwinding to %left.end, the catchendpad
-; in %inner.end unwinds to a sibling cleanup pad. Both %inner (along with its
-; associated blocks) and %inner.sibling must be cloned for %left and %right.
-; The clones of %inner will be identical, but the copy of %inner.sibling for
-; %right must end with an unreachable instruction, because it cannot unwind to
-; %left.end.
-; CHECK-LABEL: define void @test7(
-; CHECK: left:
-; CHECK: catchpad []
-; CHECK: to label %left.catch unwind label %[[LEFT_END:.+]]
-; CHECK: left.catch:
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: [[LEFT_END]]:
-; CHECK: catchendpad unwind label %[[RIGHT:.+]]
-; CHECK: [[RIGHT]]:
-; CHECK: [[R:\%.+]] = cleanuppad []
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: [[X_RELOAD_R:\%.+]] = load i32, i32* %x.wineh.spillslot
-; CHECK: call void @h(i32 [[X_RELOAD_R]])
-; CHECK: unreachable
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: [[X_RELOAD_L:\%.+]] = load i32, i32* %x.wineh.spillslot
-; CHECK: call void @h(i32 [[X_RELOAD_L]])
-; CHECK: unreachable
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind label %[[INNER_SIBLING_LEFT:.+]]
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind label %[[INNER_SIBLING_RIGHT:.+]]
-; CHECK: [[INNER_SIBLING_RIGHT]]
-; CHECK: [[IS_R:\%.+]] = cleanuppad []
-; CHECK: call void @h(i32 0)
-; CHECK: unreachable
-; CHECK: [[INNER_SIBLING_LEFT]]
-; CHECK: [[IS_L:\%.+]] = cleanuppad []
-; CHECK: call void @h(i32 0)
-; CHECK: cleanupret [[IS_L]] unwind label %[[LEFT_END]]
-
-
-define void @test8() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %invoke.cont unwind label %left
-invoke.cont:
- invoke void @f()
- to label %unreachable unwind label %right
-left:
- cleanuppad []
- invoke void @f() to label %unreachable unwind label %inner
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- invoke void @f() to label %unreachable unwind label %inner
-right.end:
- catchendpad unwind to caller
-inner:
- %i = cleanuppad []
- %x = call i32 @g()
- call void @h(i32 %x)
- cleanupret %i unwind label %right.end
-unreachable:
- unreachable
-}
-; Another case of a two-parent child (like @test1), this time
-; with the join at the entry itself instead of following a
-; non-pad join.
-; CHECK-LABEL: define void @test8(
-; CHECK: invoke.cont:
-; CHECK: to label %[[UNREACHABLE_ENTRY:.+]] unwind label %right
-; CHECK: left:
-; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: to label %right.catch unwind label %right.end
-; CHECK: right.catch:
-; CHECK: to label %unreachable unwind label %[[INNER_RIGHT:.+]]
-; CHECK: right.end:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: [[I_R:\%.+]] = cleanuppad []
-; CHECK: [[X_R:\%.+]] = call i32 @g()
-; CHECK: call void @h(i32 [[X_R]])
-; CHECK: cleanupret [[I_R]] unwind label %right.end
-; CHECK: [[INNER_LEFT]]:
-; CHECK: [[I_L:\%.+]] = cleanuppad []
-; CHECK: [[X_L:\%.+]] = call i32 @g()
-; CHECK: call void @h(i32 [[X_L]])
-; CHECK: unreachable
-; CHECK: unreachable:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_ENTRY]]:
-; CHECK: unreachable
-
-
-define void @test9() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %invoke.cont unwind label %left
-invoke.cont:
- invoke void @f()
- to label %unreachable unwind label %right
-left:
- cleanuppad []
- br label %shared
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- invoke void @f()
- to label %unreachable unwind label %inner
-inner:
- cleanuppad []
- invoke void @f()
- to label %unreachable unwind label %inner.child
-inner.child:
- cleanuppad []
- %x = call i32 @g()
- call void @h(i32 %x)
- unreachable
-unreachable:
- unreachable
-}
-; %inner is a two-parent child which itself has a child; need
-; to make two copies of both the %inner and %inner.child.
-; CHECK-LABEL: define void @test9(
-; CHECK: invoke.cont:
-; CHECK: to label %[[UNREACHABLE_ENTRY:.+]] unwind label %right
-; CHECK: left:
-; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: to label %right.catch unwind label %right.end
-; CHECK: right.catch:
-; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: right.end:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: to label %[[UNREACHABLE_INNER_RIGHT:.+]] unwind label %[[INNER_CHILD_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: to label %[[UNREACHABLE_INNER_LEFT:.+]] unwind label %[[INNER_CHILD_LEFT:.+]]
-; CHECK: [[INNER_CHILD_RIGHT]]:
-; CHECK: [[TMP:\%.+]] = cleanuppad []
-; CHECK: [[X:\%.+]] = call i32 @g()
-; CHECK: call void @h(i32 [[X]])
-; CHECK: unreachable
-; CHECK: [[INNER_CHILD_LEFT]]:
-; CHECK: [[TMP:\%.+]] = cleanuppad []
-; CHECK: [[X:\%.+]] = call i32 @g()
-; CHECK: call void @h(i32 [[X]])
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_INNER_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_INNER_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_ENTRY]]:
-; CHECK: unreachable
-
-
-define void @test10() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %invoke.cont unwind label %left
-invoke.cont:
- invoke void @f()
- to label %unreachable unwind label %right
-left:
- cleanuppad []
- call void @h(i32 1)
- invoke void @f()
- to label %unreachable unwind label %right
-right:
- cleanuppad []
- call void @h(i32 2)
- invoke void @f()
- to label %unreachable unwind label %left
-unreachable:
- unreachable
-}
-; This is an irreducible loop with two funclets that enter each other;
-; need to make two copies of each funclet (one a child of root, the
-; other a child of the opposite funclet), but also make sure not to
-; clone self-descendants (if we tried to do that we'd need to make an
-; infinite number of them). Presumably if optimizations ever generated
-; such a thing it would mean that one of the two cleanups was originally
-; the parent of the other, but that we'd somehow lost track in the CFG
-; of which was which along the way; generating each possibility lets
-; whichever case was correct execute correctly.
-; CHECK-LABEL: define void @test10(
-; CHECK: entry:
-; CHECK: to label %invoke.cont unwind label %[[LEFT:.+]]
-; CHECK: invoke.cont:
-; CHECK: to label %[[UNREACHABLE_ENTRY:.+]] unwind label %[[RIGHT:.+]]
-; CHECK: [[LEFT_FROM_RIGHT:.+]]:
-; CHECK: call void @h(i32 1)
-; CHECK: call void @f()
-; CHECK: unreachable
-; CHECK: [[LEFT]]:
-; CHECK: call void @h(i32 1)
-; CHECK: invoke void @f()
-; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[RIGHT_FROM_LEFT:.+]]
-; CHECK: [[RIGHT]]:
-; CHECK: call void @h(i32 2)
-; CHECK: invoke void @f()
-; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[LEFT_FROM_RIGHT]]
-; CHECK: [[RIGHT_FROM_LEFT]]:
-; CHECK: call void @h(i32 2)
-; CHECK: call void @f()
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[UNREACHABLE_ENTRY]]:
-; CHECK: unreachable
-
-
-define void @test11() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %exit unwind label %left
-left:
- catchpad []
- to label %left.catch unwind label %left.sibling
-left.catch:
- br label %shared
-left.sibling:
- %ls = catchpad []
- to label %left.sibling.catch unwind label %left.end
-left.sibling.catch:
- catchret %ls to label %exit
-left.end:
- catchendpad unwind label %right
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- %x = call i32 @g()
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 %x)
- unreachable
-inner.end:
- catchendpad unwind label %left.end
-exit:
- ret void
-}
-; This is a variation of @test4 in which the shared child funclet unwinds to a
-; catchend pad that is the unwind destination of %left.sibling rather than %left
-; but is still a valid destination for %inner as reach from %left.
-; When %inner is cloned a copy of %inner.end will be made for both %left and
-; %right, but because the catchpad in %right does not unwind to %left.end the
-; unwind edge from the copy of %inner.end for %right must be removed.
-; CHECK-LABEL: define void @test11(
-; CHECK: left:
-; CHECK: catchpad []
-; CHECK: to label %left.catch unwind label %left.sibling
-; CHECK: left.catch:
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: left.sibling:
-; CHECK: catchpad []
-; CHECK: to label %left.sibling.catch unwind label %[[LEFT_END:.+]]
-; CHECK: [[LEFT_END]]:
-; CHECK: catchendpad unwind label %right
-; CHECK: right:
-; CHECK: to label %right.catch unwind label %[[RIGHT_END:.+]]
-; CHECK: right.catch:
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: [[X_RELOAD_R:\%.+]] = load i32, i32* %x.wineh.spillslot
-; CHECK: call void @h(i32 [[X_RELOAD_R]])
-; CHECK: unreachable
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: [[X_RELOAD_L:\%.+]] = load i32, i32* %x.wineh.spillslot
-; CHECK: call void @h(i32 [[X_RELOAD_L]])
-; CHECK: unreachable
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind label %[[LEFT_END]]
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind to caller
-
-
-define void @test12() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %exit unwind label %left
-left:
- catchpad []
- to label %left.catch unwind label %right
-left.catch:
- br label %shared
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- %x = call i32 @g()
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 %x)
- unreachable
-inner.end:
- catchendpad unwind label %right.end
-exit:
- ret void
-}
-; In this case %left and %right are both parents of %inner, so %inner must be
-; cloned but the catchendpad unwind target in %inner.end is valid for both
-; parents, so the unwind edge should not be removed in either case.
-; CHECK-LABEL: define void @test12(
-; CHECK: left:
-; CHECK: catchpad []
-; CHECK: to label %left.catch unwind label %right
-; CHECK: left.catch:
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: to label %right.catch unwind label %[[RIGHT_END:.+]]
-; CHECK: right.catch:
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: [[X_RELOAD_R:\%.+]] = load i32, i32* %x.wineh.spillslot
-; CHECK: call void @h(i32 [[X_RELOAD_R]])
-; CHECK: unreachable
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: [[X_RELOAD_L:\%.+]] = load i32, i32* %x.wineh.spillslot
-; CHECK: call void @h(i32 [[X_RELOAD_L]])
-; CHECK: unreachable
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind label %[[RIGHT_END]]
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind label %[[RIGHT_END]]
-
-define void @test13() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %invoke.cont unwind label %left
-invoke.cont:
- invoke void @f()
- to label %exit unwind label %right
-left:
- %l = catchpad []
- to label %left.cont unwind label %left.end
-left.cont:
- invoke void @f()
- to label %left.ret unwind label %inner
-left.ret:
- catchret %l to label %invoke.cont
-left.end:
- catchendpad unwind to caller
-right:
- %r = catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- invoke void @f()
- to label %right.ret unwind label %inner
-right.ret:
- catchret %r to label %exit
-right.end:
- catchendpad unwind to caller
-shared:
- call void @h(i32 0)
- unreachable
-inner:
- %i = catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 1)
- catchret %i to label %shared
-inner.end:
- catchendpad unwind label %left.end
-exit:
- ret void
-}
-; This case tests the scenario where a funclet with multiple parents uses a
-; catchret to return to a block that may exist in either parent funclets.
-; Both %left and %right are parents of %inner. During common block cloning
-; a clone of %shared will be made so that both %left and %right have a copy,
-; but the copy of %shared for one of the parent funclets will be unreachable
-; until the %inner funclet is cloned. When the %inner.catch block is cloned
-; during the %inner funclet cloning, the catchret instruction should be updated
-; so that the catchret in the copy %inner.catch for %left returns to the copy of
-; %shared in %left and the catchret in the copy of %inner.catch for %right
-; returns to the copy of %shared for %right.
-; CHECK-LABEL: define void @test13(
-; CHECK: left:
-; CHECK: %l = catchpad []
-; CHECK: to label %left.cont unwind label %left.end
-; CHECK: left.cont:
-; CHECK: invoke void @f()
-; CHECK: to label %left.ret unwind label %[[INNER_LEFT:.+]]
-; CHECK: left.ret:
-; CHECK: catchret %l to label %invoke.cont
-; CHECK: left.end:
-; CHECK: catchendpad unwind to caller
-; CHECK: right:
-; CHECK: %r = catchpad []
-; CHECK: to label %right.catch unwind label %right.end
-; CHECK: right.catch:
-; CHECK: invoke void @f()
-; CHECK: to label %right.ret unwind label %[[INNER_RIGHT:.+]]
-; CHECK: right.ret:
-; CHECK: catchret %r to label %exit
-; CHECK: right.end:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[SHARED_RIGHT:.+]]:
-; CHECK: call void @h(i32 0)
-; CHECK: unreachable
-; CHECK: [[SHARED_LEFT:.+]]:
-; CHECK: call void @h(i32 0)
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: %[[I_RIGHT:.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: %[[I_LEFT:.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: call void @h(i32 1)
-; CHECK: catchret %[[I_RIGHT]] to label %[[SHARED_RIGHT]]
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: call void @h(i32 1)
-; CHECK: catchret %[[I_LEFT]] to label %[[SHARED_LEFT]]
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind label %[[LEFT_END]]
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind to caller
-
-
-define void @test14() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %exit unwind label %left
-left:
- %l = catchpad []
- to label %shared unwind label %left.end
-left.cont:
- invoke void @f()
- to label %left.ret unwind label %right
-left.ret:
- catchret %l to label %exit
-left.end:
- catchendpad unwind to caller
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind label %left.end
-shared:
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- %i = catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 0)
- catchret %i to label %left.cont
-inner.end:
- catchendpad unwind label %left.end
-exit:
- ret void
-}
-; This case tests another scenario where a funclet with multiple parents uses a
-; catchret to return to a block in one of the parent funclets. Here %right and
-; %left are both parents of %inner and %left is a parent of %right. The
-; catchret in %inner.catch will cause %left.cont and %left.ret to be cloned for
-; both %left and %right, but the catchret in %left.ret is invalid for %right
-; but the catchret instruction in the copy of %left.ret for %right will be
-; removed as an implausible terminator.
-; CHECK-LABEL: define void @test14(
-; CHECK: left:
-; CHECK: %l = catchpad []
-; CHECK: to label %[[SHARED_LEFT:.+]] unwind label %[[LEFT_END:.+]]
-; CHECK: [[LEFT_CONT:left.cont.*]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[LEFT_RET:.+]] unwind label %[[RIGHT:.+]]
-; CHECK: [[LEFT_RET]]:
-; CHECK: catchret %l to label %exit
-; CHECK: [[LEFT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[RIGHT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[RIGHT_CATCH:.+]] unwind label %[[RIGHT_END:.+]]
-; CHECK: [[RIGHT_CATCH]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind label %[[LEFT_END]]
-; CHECK: [[SHARED_LEFT]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_LEFT]]:
-; CHECK: [[I_LEFT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: [[I_RIGHT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: call void @h(i32 0)
-; CHECK: catchret [[I_LEFT]] to label %[[LEFT_CONT]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: call void @h(i32 0)
-; CHECK: unreachable
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind label %[[LEFT_END]]
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind to caller
-
-define void @test15() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %exit unwind label %left
-left:
- %l = catchpad []
- to label %left.catch unwind label %left.end
-left.catch:
- invoke void @f()
- to label %shared unwind label %right
-left.ret:
- catchret %l to label %exit
-left.end:
- catchendpad unwind to caller
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind label %left.end
-shared:
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- %i = catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 0)
- catchret %i to label %left.ret
-inner.end:
- catchendpad unwind label %left.end
-exit:
- ret void
-}
-; This case is a variation of test14 but instead of returning to an invoke the
-; catchret in %inner.catch returns to a catchret instruction.
-; CHECK-LABEL: define void @test15(
-; CHECK: left:
-; CHECK: %l = catchpad []
-; CHECK: to label %left.catch unwind label %[[LEFT_END:.+]]
-; CHECK: left.catch:
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_LEFT:.+]] unwind label %[[RIGHT:.+]]
-; CHECK: [[LEFT_RET_RIGHT:.+]]:
-; CHECK: unreachable
-; CHECK: [[LEFT_RET_LEFT:.+]]:
-; CHECK: catchret %l to label %exit
-; CHECK: [[LEFT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[RIGHT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[RIGHT_CATCH:.+]] unwind label %[[RIGHT_END:.+]]
-; CHECK: [[RIGHT_CATCH]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind label %[[LEFT_END]]
-; CHECK: [[SHARED_LEFT]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_LEFT]]:
-; CHECK: [[I_LEFT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: [[I_RIGHT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: call void @h(i32 0)
-; CHECK: catchret [[I_LEFT]] to label %[[LEFT_RET_LEFT]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: call void @h(i32 0)
-; CHECK: catchret [[I_RIGHT]] to label %[[LEFT_RET_RIGHT]]
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind label %[[LEFT_END]]
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind to caller
-
-
-define void @test16() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %exit unwind label %left
-left:
- %l = cleanuppad []
- br label %shared
-left.cont:
- cleanupret %l unwind label %right
-left.end:
- cleanupendpad %l unwind label %right
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- invoke void @f()
- to label %shared.cont unwind label %inner
-shared.cont:
- unreachable
-inner:
- %i = catchpad []
- to label %inner.catch unwind label %inner.end
-inner.catch:
- call void @h(i32 0)
- catchret %i to label %left.cont
-inner.end:
- catchendpad unwind label %left.end
-exit:
- ret void
-}
-; This case is another variation of test14 but here the catchret in %inner.catch
-; returns to a cleanupret instruction.
-; CHECK-LABEL: define void @test16(
-; CHECK: left:
-; CHECK: %l = cleanuppad []
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: [[LEFT_CONT_RIGHT:.+]]:
-; CHECK: unreachable
-; CHECK: [[LEFT_CONT_LEFT:.+]]:
-; CHECK: cleanupret %l unwind label %[[RIGHT:.+]]
-; CHECK: [[LEFT_END_LEFT:.+]]:
-; CHECK: cleanupendpad %l unwind label %[[RIGHT]]
-; CHECK: [[RIGHT]]:
-; CHECK: catchpad []
-; CHECK: to label %[[RIGHT_CATCH:.+]] unwind label %[[RIGHT_END:.+]]
-; CHECK: [[RIGHT_CATCH]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: [[I_RIGHT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: [[I_LEFT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: call void @h(i32 0)
-; CHECK: catchret [[I_RIGHT]] to label %[[LEFT_CONT_RIGHT]]
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: call void @h(i32 0)
-; CHECK: catchret [[I_LEFT]] to label %[[LEFT_CONT_LEFT]]
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind label %[[LEFT_END_LEFT]]
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind to caller
-
-
-define void @test17() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %invoke.cont unwind label %left
-invoke.cont:
- invoke void @f()
- to label %exit unwind label %right
-left:
- %l = cleanuppad []
- br label %shared
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- invoke void @f()
- to label %unreachable unwind label %inner
-unreachable:
- unreachable
-inner:
- %i = catchpad []
- to label %inner.catch unwind label %inner.sibling
-inner.catch:
- call void @h(i32 0)
- unreachable
-inner.sibling:
- %is = catchpad []
- to label %inner.sibling.catch unwind label %inner.end
-inner.sibling.catch:
- invoke void @f()
- to label %unreachable unwind label %inner.end
-inner.end:
- catchendpad unwind label %right.end
-exit:
- ret void
-}
-; This case tests the scenario where two catchpads with the same catchendpad
-; have multiple parents. Both %left and %right are parents of %inner and
-; %inner.sibling so both of the inner funclets must be cloned. Because
-; the catchendpad in %inner.end unwinds to the catchendpad for %right, the
-; unwind edge should be removed for the copy of %inner.end that is reached
-; from %left. In addition, the %inner.siblin.catch block contains an invoke
-; that unwinds to the shared inner catchendpad. The unwind destination for
-; this invoke should be updated to unwind to the correct cloned %inner.end
-; for each path to the funclet.
-; CHECK-LABEL: define void @test17(
-; CHECK: left:
-; CHECK: %l = cleanuppad []
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: catchpad []
-; CHECK: to label %[[RIGHT_CATCH:.+]] unwind label %[[RIGHT_END:.+]]
-; CHECK: [[RIGHT_CATCH]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: [[I_RIGHT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_SIBLING_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: [[I_LEFT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_SIBLING_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: call void @h(i32 0)
-; CHECK: unreachable
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: call void @h(i32 0)
-; CHECK: unreachable
-; CHECK: [[INNER_SIBLING_RIGHT]]:
-; CHECK: [[IS_RIGHT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_SIBLING_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_SIBLING_LEFT]]:
-; CHECK: [[IS_LEFT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_SIBLING_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_SIBLING_CATCH_RIGHT]]:
-; CHECK: invoke void @f()
-; TODO: Re-enable this check when it is less flaky.
-; to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[INNER_END_RIGHT]]
-; CHECK: [[INNER_SIBLING_CATCH_LEFT]]:
-; CHECK: invoke void @f()
-; TODO: Re-enable this check when it is less flaky.
-; to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_END_LEFT]]
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind label %[[RIGHT_END]]
-
-
-define void @test18() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %invoke.cont unwind label %left
-invoke.cont:
- invoke void @f()
- to label %exit unwind label %right
-left:
- %l = cleanuppad []
- br label %shared
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- invoke void @f()
- to label %unreachable unwind label %inner
-unreachable:
- unreachable
-inner:
- %i = catchpad []
- to label %inner.catch unwind label %inner.sibling
-inner.catch:
- invoke void @f()
- to label %unreachable unwind label %inner.end
-inner.sibling:
- %is = catchpad []
- to label %inner.sibling.catch unwind label %inner.end
-inner.sibling.catch:
- call void @h(i32 0)
- unreachable
-inner.end:
- catchendpad unwind label %right.end
-exit:
- ret void
-}
-; This is like test17 except that the inner invoke is moved from the
-; %inner.sibling funclet to %inner so that it is unwinding to a
-; catchendpad block that has not yet been cloned. The unwind destination
-; of the invoke should still be updated to reach the correct copy of
-; %inner.end for the path by which it is reached.
-; CHECK-LABEL: define void @test18(
-; CHECK: left:
-; CHECK: %l = cleanuppad []
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: catchpad []
-; CHECK: to label %[[RIGHT_CATCH:.+]] unwind label %[[RIGHT_END:.+]]
-; CHECK: [[RIGHT_CATCH]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: [[I_RIGHT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_RIGHT:.+]] unwind label %[[INNER_SIBLING_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: [[I_LEFT:\%.+]] = catchpad []
-; CHECK: to label %[[INNER_CATCH_LEFT:.+]] unwind label %[[INNER_SIBLING_LEFT:.+]]
-; CHECK: [[INNER_CATCH_RIGHT]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_CATCH_LEFT]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_SIBLING_RIGHT]]:
-; CHECK: [[IS_RIGHT:\%.+]] = catchpad []
-; TODO: Re-enable this check when it is less flaky.
-; to label %[[INNER_SIBLING_CATCH_RIGHT:.+]] unwind label %[[INNER_END_RIGHT]]
-; CHECK: [[INNER_SIBLING_LEFT]]:
-; CHECK: [[IS_LEFT:\%.+]] = catchpad []
-; TODO: Re-enable this check when it is less flaky.
-; to label %[[INNER_SIBLING_CATCH_LEFT:.+]] unwind label %[[INNER_END_LEFT]]
-; CHECK: [[INNER_SIBLING_CATCH_RIGHT]]:
-; CHECK: call void @h(i32 0)
-; CHECK: unreachable
-; CHECK: [[INNER_SIBLING_CATCH_LEFT]]:
-; CHECK: call void @h(i32 0)
-; CHECK: unreachable
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: catchendpad unwind label %[[RIGHT_END]]
-
-
-define void @test19() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %invoke.cont unwind label %left
-invoke.cont:
- invoke void @f()
- to label %exit unwind label %right
-left:
- %l = cleanuppad []
- br label %shared
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- invoke void @f()
- to label %unreachable unwind label %inner
-unreachable:
- unreachable
-inner:
- %i = cleanuppad []
- invoke void @f()
- to label %unreachable unwind label %inner.end
-inner.end:
- cleanupendpad %i unwind label %right.end
-exit:
- ret void
-}
-; This case tests the scenario where an invoke in a funclet with multiple
-; parents unwinds to a cleanup end pad for the funclet. The unwind destination
-; for the invoke should map to the correct copy of the cleanup end pad block.
-; CHECK-LABEL: define void @test19(
-; CHECK: left:
-; CHECK: %l = cleanuppad []
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: catchpad []
-; CHECK: to label %[[RIGHT_CATCH:.+]] unwind label %[[RIGHT_END:.+]]
-; CHECK: [[RIGHT_CATCH]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: [[I_RIGHT:\%.+]] = cleanuppad []
-; CHECK: invoke void @f()
-; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[INNER_END_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: [[I_LEFT:\%.+]] = cleanuppad []
-; CHECK: invoke void @f()
-; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_END_LEFT:.+]]
-; CHECK: [[INNER_END_RIGHT]]:
-; CHECK: cleanupendpad [[I_RIGHT]] unwind label %[[RIGHT_END]]
-; CHECK: [[INNER_END_LEFT]]:
-; CHECK: cleanupendpad [[I_LEFT]] unwind to caller
-
-define void @test20() personality i32 (...)* @__CxxFrameHandler3 {
-entry:
- invoke void @f()
- to label %invoke.cont unwind label %left
-invoke.cont:
- invoke void @f()
- to label %exit unwind label %right
-left:
- %l = cleanuppad []
- br label %shared
-right:
- catchpad []
- to label %right.catch unwind label %right.end
-right.catch:
- br label %shared
-right.end:
- catchendpad unwind to caller
-shared:
- invoke void @f()
- to label %unreachable unwind label %inner
-unreachable:
- unreachable
-inner:
- %i = cleanuppad []
- invoke void @f()
- to label %unreachable unwind label %inner.cleanup
-inner.cleanup:
- cleanuppad []
- call void @f()
- unreachable
-exit:
- ret void
-}
-; This tests the case where a funclet with multiple parents contains an invoke
-; instruction that unwinds to a child funclet. Here %left and %right are both
-; parents of %inner. Initially %inner is the only parent of %inner.cleanup but
-; after %inner is cloned, %inner.cleanup has multiple parents and so it must
-; also be cloned.
-; CHECK-LABEL: define void @test20(
-; CHECK: left:
-; CHECK: %l = cleanuppad []
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]]
-; CHECK: right:
-; CHECK: catchpad []
-; CHECK: to label %[[RIGHT_CATCH:.+]] unwind label %[[RIGHT_END:.+]]
-; CHECK: [[RIGHT_CATCH]]:
-; CHECK: invoke void @f()
-; CHECK: to label %[[SHARED_CONT_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]]
-; CHECK: [[RIGHT_END]]:
-; CHECK: catchendpad unwind to caller
-; CHECK: [[SHARED_CONT_RIGHT]]:
-; CHECK: unreachable
-; CHECK: [[SHARED_CONT_LEFT]]:
-; CHECK: unreachable
-; CHECK: [[INNER_RIGHT]]:
-; CHECK: [[I_RIGHT:\%.+]] = cleanuppad []
-; CHECK: invoke void @f()
-; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[INNER_CLEANUP_RIGHT:.+]]
-; CHECK: [[INNER_LEFT]]:
-; CHECK: [[I_LEFT:\%.+]] = cleanuppad []
-; CHECK: invoke void @f()
-; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_CLEANUP_LEFT:.+]]
-; CHECK: [[INNER_CLEANUP_RIGHT]]:
-; CHECK: cleanuppad []
-; CHECK: call void @f()
-; CHECK: unreachable
-; CHECK: [[INNER_CLEANUP_LEFT]]:
-; CHECK: cleanuppad []
-; CHECK: call void @f()
-; CHECK: unreachable
-
-
Modified: llvm/trunk/test/CodeGen/WinEH/wineh-no-demotion.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WinEH/wineh-no-demotion.ll?rev=252279&r1=252278&r2=252279&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WinEH/wineh-no-demotion.ll (original)
+++ llvm/trunk/test/CodeGen/WinEH/wineh-no-demotion.ll Fri Nov 6 04:07:33 2015
@@ -39,20 +39,12 @@ shared.cont:
unreachable
inner:
+ ; CHECK: %phi = phi i32 [ %x, %right ], [ 0, %invoke.cont2 ], [ %x.for.left, %left ]
%phi = phi i32 [ %x, %shared ], [ 0, %invoke.cont2 ]
%i = cleanuppad []
call void @h(i32 %phi)
unreachable
-; CHECK [[INNER_INVOKE_CONT2:inner.*]]:
- ; CHECK: call void @h(i32 0)
-
-; CHECK [[INNER_RIGHT:inner.*]]:
- ; CHECK: call void @h(i32 %x)
-
-; CHECK [[INNER_LEFT:inner.*]]:
- ; CHECK: call void @h(i32 %x.for.left)
-
exit:
unreachable
}
@@ -84,16 +76,12 @@ shared.cont:
unreachable
inner:
+ ; CHECK: %x1 = phi i32 [ %x.for.left, %left ], [ %x, %right ]
+ ; CHECK: call void @h(i32 %x1)
%i = cleanuppad []
call void @h(i32 %x)
unreachable
-; CHECK [[INNER_RIGHT:inner.*]]:
- ; CHECK: call void @h(i32 %x)
-
-; CHECK [[INNER_LEFT:inner.*]]:
- ; CHECK: call void @h(i32 %x.for.left)
-
exit:
unreachable
}
More information about the llvm-commits
mailing list