From: NAKAMURA Takumi Date: Fri, 6 Nov 2015 10:07:33 +0000 (+0000) Subject: Revert r252249 (and r252255, r252258), "[WinEH] Clone funclets with multiple parents" X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=commitdiff_plain;h=353c554d981dae4fb0535ceb81e9017211ac1a78 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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@252279 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index 7774a70f5f4..1c219ad6cd8 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -5322,8 +5322,7 @@ bool LLParser::ParseCleanupEndPad(Instruction *&Inst, PerFunctionState &PFS) { 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)) { diff --git a/lib/CodeGen/WinEHPrepare.cpp b/lib/CodeGen/WinEHPrepare.cpp index 7b0dbd0c395..ca69d321f3b 100644 --- a/lib/CodeGen/WinEHPrepare.cpp +++ b/lib/CodeGen/WinEHPrepare.cpp @@ -74,20 +74,6 @@ private: SmallVectorImpl &EntryBlocks); void replaceTerminatePadWithCleanup(Function &F); void colorFunclets(Function &F, SmallVectorImpl &EntryBlocks); - void resolveFuncletAncestry(Function &F, - SmallVectorImpl &EntryBlocks); - void resolveFuncletAncestryForPath( - Function &F, SmallVectorImpl &FuncletPath, - std::map &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 &Orig2Clone); - void demotePHIsOnFunclets(Function &F); void demoteUsesBetweenFunclets(Function &F); void demoteArgumentUses(Function &F); @@ -102,18 +88,7 @@ private: std::map> BlockColors; std::map> FuncletBlocks; - std::map> FuncletChildren; - std::map> 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> EstrangedBlocks; + std::map> FuncletChildren; }; } // end anonymous namespace @@ -584,7 +559,8 @@ void WinEHPrepare::replaceTerminatePadWithCleanup(Function &F) { static void colorFunclets(Function &F, SmallVectorImpl &EntryBlocks, std::map> &BlockColors, - std::map> &FuncletBlocks) { + std::map> &FuncletBlocks, + std::map> &FuncletChildren) { SmallVector, 16> Worklist; BasicBlock *EntryBlock = &F.getEntryBlock(); @@ -601,18 +577,12 @@ colorFunclets(Function &F, SmallVectorImpl &EntryBlocks, // 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(VisitingHead) && !isa(VisitingHead)) { @@ -630,13 +600,8 @@ colorFunclets(Function &F, SmallVectorImpl &EntryBlocks, if (auto *Exit = dyn_cast(U)) { for (BasicBlock *Succ : successors(Exit->getParent())) if (!isa(*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, SmallVectorImpl &EntryBlocks, // 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, SmallVectorImpl &EntryBlocks, 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(UnwindTerminator)) { - NextUnwindDest = NextCatch->getUnwindDest(); - UnwindTerminator = NextUnwindDest->getTerminator(); - } - // The last catch in the chain must unwind to a catchendpad. - assert(isa(UnwindTerminator)); - return NextUnwindDest; -} - -static void updateClonedEHPadUnwindToParent( - BasicBlock *UnwindDest, BasicBlock *OrigBlock, BasicBlock *CloneBlock, - std::vector &OrigParents, BasicBlock *CloneParent) { - auto updateUnwindTerminator = [](BasicBlock *BB) { - auto *Terminator = BB->getTerminator(); - if (isa(Terminator) || - isa(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(Terminator) || - isa(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(EHPadInst)) { - auto *CloneParentCatch = - dyn_cast(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(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(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(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(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(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(EHPadInst) || isa(EHPadInst) || - isa(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 &OrigParents, BasicBlock *CloneParent, - ValueToValueMapTy &VMap, - std::map> &BlockColors, - std::map> &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(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(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 &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(CloneTerminator)) { - // A cloned catch pad has a lot of wrinkles, so we'll call a helper function - // to update this case. - auto *OrigCatch = cast(OrigBlock->getTerminator()); - updateCatchTerminators(F, OrigCatch, CloneCatch, - FuncletParents[OrigFunclet], CloneParent, VMap, - BlockColors, FuncletBlocks); - } else if (auto *CRI = dyn_cast(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(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(CloneTerminator) || - isa(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(CloneTerminator)) - UnwindDest = CRI->getUnwindDest(); - else if (auto *CEI = dyn_cast(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(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(EHPadInst)) { - // An invoke that unwinds to a cleanup end pad must be in a cleanup pad. - assert(isa(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(EHPadInst)) { - auto *OrigCatch = cast(OrigFunclet->getFirstNonPHI()); - auto *CloneCatch = cast(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(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 &BlocksInFunclet = FuncletBlocks[FuncletEntry]; - - DEBUG_WITH_TYPE("winehprepare-coloring", - dbgs() << "Cloning funclet \'" << FuncletEntry->getName() - << "\' for parent \'" << Parent->getName() << "\'.\n"); - - std::map 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 &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(&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(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 &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(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 PHIsToErase; - for (Instruction &I : *ClonedFunclet) { - auto *PN = dyn_cast(&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(Terminator)) - UnwindDest = I->getUnwindDest(); - else if (auto *I = dyn_cast(Terminator)) - UnwindDest = I->getUnwindDest(); - else if (auto *I = dyn_cast(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 &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> &BlockColors, - std::map> &FuncletBlocks, - std::map> &FuncletParents, - std::map> &FuncletChildren, - std::map &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(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(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(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(Terminator)) { - UnwindDest = I->getUnwindDest(); - // The catchendpad is not a sibling destination. This case should - // have been handled in cloneFuncletForParent(). - if (isa(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(Terminator)) - UnwindDest = I->getUnwindDest(); - else if (auto *I = dyn_cast(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(EHPad) && !isa(EHPad) && - !isa(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(Terminator)) - I->setUnwindDest(TargetSibling); - else if (auto *I = dyn_cast(Terminator)) - I->setUnwindDest(TargetSibling); - else if (auto *I = dyn_cast(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(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(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(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 &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 Funclet2Orig; - for (auto *Funclet : EntryBlocks) - Funclet2Orig[Funclet] = Funclet; - - // Start with the entry funclet and walk the funclet parent-child tree. - SmallVector 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 &FuncletPath, - std::map &Funclet2Orig) { - bool ClonedAnyChildren = false; - BasicBlock *CurFunclet = FuncletPath.back(); - // Copy the children vector because we might changing it. - std::vector 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 &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(Function &F, // that transitions to the child funclet). for (BasicBlock *FuncletEntry : EntryBlocks) { std::set &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 &EntryBlocks) { + ::colorFunclets(F, EntryBlocks, BlockColors, FuncletBlocks, FuncletChildren); +} + void llvm::calculateCatchReturnSuccessorColors(const Function *Fn, WinEHFuncInfo &FuncInfo) { SmallVector EntryBlocks; @@ -1526,18 +678,10 @@ void llvm::calculateCatchReturnSuccessorColors(const Function *Fn, std::map> BlockColors; std::map> FuncletBlocks; + std::map> FuncletChildren; // Figure out which basic blocks belong to which funclets. colorFunclets(const_cast(*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 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 &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(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(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(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; } diff --git a/test/CodeGen/WinEH/wineh-cloning.ll b/test/CodeGen/WinEH/wineh-cloning.ll index 58bf71e62b6..b4e785d42dd 100644 --- a/test/CodeGen/WinEH/wineh-cloning.ll +++ b/test/CodeGen/WinEH/wineh-cloning.ll @@ -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: diff --git a/test/CodeGen/WinEH/wineh-demotion.ll b/test/CodeGen/WinEH/wineh-demotion.ll index e849a8ec80c..113d95015a0 100644 --- a/test/CodeGen/WinEH/wineh-demotion.ll +++ b/test/CodeGen/WinEH/wineh-demotion.ll @@ -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: diff --git a/test/CodeGen/WinEH/wineh-multi-parent-cloning.ll b/test/CodeGen/WinEH/wineh-multi-parent-cloning.ll deleted file mode 100644 index 96028542671..00000000000 --- a/test/CodeGen/WinEH/wineh-multi-parent-cloning.ll +++ /dev/null @@ -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 - - diff --git a/test/CodeGen/WinEH/wineh-no-demotion.ll b/test/CodeGen/WinEH/wineh-no-demotion.ll index 4f023947caa..4e4206eb2be 100644 --- a/test/CodeGen/WinEH/wineh-no-demotion.ll +++ b/test/CodeGen/WinEH/wineh-no-demotion.ll @@ -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 }