diff --git a/llvm/lib/Analysis/CGSCCPassManager.cpp b/llvm/lib/Analysis/CGSCCPassManager.cpp --- a/llvm/lib/Analysis/CGSCCPassManager.cpp +++ b/llvm/lib/Analysis/CGSCCPassManager.cpp @@ -468,9 +468,8 @@ if (auto *CB = dyn_cast(&I)) if (Function *Callee = CB->getCalledFunction()) if (Visited.insert(Callee).second && !Callee->isDeclaration()) { - Node *CalleeN = G.lookup(*Callee); - if (!CalleeN) { - CalleeN = &G.get(*Callee); + Node *CalleeN = &G.get(*Callee); + if (!CalleeN->isPopulated()) { NewNodes.insert(CalleeN); } Edge *E = N->lookup(*CalleeN); @@ -495,9 +494,8 @@ Worklist.push_back(C); auto VisitRef = [&](Function &Referee) { - Node *RefereeN = G.lookup(Referee); - if (!RefereeN) { - RefereeN = &G.get(Referee); + Node *RefereeN = &G.get(Referee); + if (!RefereeN->isPopulated()) { NewNodes.insert(RefereeN); } Edge *E = N->lookup(*RefereeN); @@ -515,9 +513,30 @@ }; LazyCallGraph::visitReferences(Worklist, Visited, VisitRef); - for (Node *NewNode : NewNodes) + while (!NewNodes.empty()) { + Node *NewNode = NewNodes.pop_back_val(); + if (NewNode->isPopulated()) + continue; G.initNode(*NewNode, *C); + SmallVector NewNodesWorklist; + SmallPtrSet NewNodesVisited; + + for (Instruction &I : instructions(NewNode->getFunction())) + for (Value *Op : I.operand_values()) + if (auto *C = dyn_cast(Op)) + if (NewNodesVisited.insert(C).second) + NewNodesWorklist.push_back(C); + + auto CheckNewNode = [&](Function &Referee) { + if (!G.get(Referee).isPopulated()) + NewNodes.insert(&G.get(Referee)); + }; + + LazyCallGraph::visitReferences(NewNodesWorklist, NewNodesVisited, + CheckNewNode); + } + // Handle new ref edges. for (Node *RefTarget : NewRefEdges) { SCC &TargetC = *G.lookupSCC(*RefTarget); diff --git a/llvm/test/Transforms/Coroutines/coro-retcon-resume-values2.ll b/llvm/test/Transforms/Coroutines/coro-retcon-resume-values2.ll --- a/llvm/test/Transforms/Coroutines/coro-retcon-resume-values2.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon-resume-values2.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -coro-split -coro-cleanup -S | FileCheck %s +; RUN: opt < %s -passes=coro-split,coro-cleanup -S | FileCheck %s define i8* @f(i8* %buffer, i32 %n) "coroutine.presplit"="1" { entry: diff --git a/llvm/unittests/Analysis/CGSCCPassManagerTest.cpp b/llvm/unittests/Analysis/CGSCCPassManagerTest.cpp --- a/llvm/unittests/Analysis/CGSCCPassManagerTest.cpp +++ b/llvm/unittests/Analysis/CGSCCPassManagerTest.cpp @@ -1765,6 +1765,51 @@ MPM.run(*M, MAM); } +TEST_F(CGSCCPassManagerTest, TestInsertionOfNewRefSCCIndirect) { + std::unique_ptr M = parseIR("define void @f() {\n" + "entry:\n" + " ret void\n" + "}\n"); + + CGSCCPassManager CGPM(/*DebugLogging*/ true); + CGPM.addPass(LambdaSCCPassNoPreserve([&](LazyCallGraph::SCC &C, + CGSCCAnalysisManager &AM, + LazyCallGraph &CG, + CGSCCUpdateResult &UR) { + auto &FAM = + AM.getResult(C, CG).getManager(); + + for (auto &N : C) { + auto &F = N.getFunction(); + if (F.getName() != "f") + continue; + + // Create new functions g and h. + auto *G = Function::Create(F.getFunctionType(), F.getLinkage(), + F.getAddressSpace(), "g", F.getParent()); + auto *H = Function::Create(F.getFunctionType(), F.getLinkage(), + F.getAddressSpace(), "h", F.getParent()); + // Create f -> g -> h call edges. + BasicBlock *GBB = + BasicBlock::Create(F.getParent()->getContext(), "entry", G); + BasicBlock *HBB = + BasicBlock::Create(F.getParent()->getContext(), "entry", H); + (void)CallInst::Create(G, {}, "", &F.getEntryBlock().front()); + (void)CallInst::Create(H, {}, "", GBB); + (void)ReturnInst::Create(G->getContext(), GBB); + (void)ReturnInst::Create(H->getContext(), HBB); + + ASSERT_NO_FATAL_FAILURE( + updateCGAndAnalysisManagerForCGSCCPass(CG, C, N, AM, UR, FAM)) + << "Updating the call graph with f -> g -> h caused a fatal failure"; + } + })); + + ModulePassManager MPM(/*DebugLogging*/ true); + MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); + MPM.run(*M, MAM); +} + TEST_F(CGSCCPassManagerTest, TestInsertionOfNewRefSCCMutuallyRecursive) { std::unique_ptr M = parseIR("define void @f() {\n" "entry:\n" @@ -1793,9 +1838,9 @@ BasicBlock::Create(F.getParent()->getContext(), "entry", G1); BasicBlock *G2BB = BasicBlock::Create(F.getParent()->getContext(), "entry", G2); - (void)CallInst::Create(G1, {}, "", G1BB); - (void)ReturnInst::Create(G1->getContext(), G1BB); (void)CallInst::Create(G2, {}, "", G1BB); + (void)ReturnInst::Create(G1->getContext(), G1BB); + (void)CallInst::Create(G1, {}, "", G2BB); (void)ReturnInst::Create(G2->getContext(), G2BB); // Add 'f -> g1' call edge.