Skip to content

Commit 449a135

Browse files
committed
Add LazyCallGraph API to add function to RefSCC
Summary: Depends on https://reviews.llvm.org/D70927. `LazyCallGraph::addNewFunctionIntoSCC` allows users to insert a new function node into a call graph, into a specific, existing SCC. Extend this interface such that functions can be added even when they do not belong in any existing SCC, but instead in a new SCC within an existing RefSCC. The ability to insert new functions as part of a RefSCC is necessary for outlined functions that do not form a strongly connected cycle with the function they are outlined from. An example of such a function would be the coroutine funclets 'f.resume', etc., which are outlined from a coroutine 'f'. Coroutine 'f' only references the funclets' addresses, it does not call them directly. Reviewers: jdoerfert, chandlerc, wenlei, hfinkel Reviewed By: jdoerfert Subscribers: hfinkel, JonChesterfield, mehdi_amini, hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D72226
1 parent 489f62e commit 449a135

File tree

4 files changed

+128
-6
lines changed

4 files changed

+128
-6
lines changed

llvm/include/llvm/Analysis/LazyCallGraph.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,6 +1061,10 @@ class LazyCallGraph {
10611061
/// Introduce a node for the function \p NewF in the SCC \p C.
10621062
void addNewFunctionIntoSCC(Function &NewF, SCC &C);
10631063

1064+
/// Introduce a node for the function \p NewF, as a single node in a
1065+
/// new SCC, in the RefSCC \p RC.
1066+
void addNewFunctionIntoRefSCC(Function &NewF, RefSCC &RC);
1067+
10641068
///@}
10651069

10661070
///@{
@@ -1167,6 +1171,13 @@ class LazyCallGraph {
11671171
/// Helper to update pointers back to the graph object during moves.
11681172
void updateGraphPtrs();
11691173

1174+
/// Helper to insert a new function, add it to the NodeMap, and populate its
1175+
/// node.
1176+
Node &createNode(Function &F);
1177+
1178+
/// Helper to add the given Node \p N to the SCCMap, mapped to the SCC \p C.
1179+
void addNodeToSCC(SCC &C, Node &N);
1180+
11701181
/// Allocates an SCC and constructs it using the graph allocator.
11711182
///
11721183
/// The arguments are forwarded to the constructor.

llvm/lib/Analysis/LazyCallGraph.cpp

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1567,12 +1567,17 @@ void LazyCallGraph::removeDeadFunction(Function &F) {
15671567
}
15681568

15691569
void LazyCallGraph::addNewFunctionIntoSCC(Function &NewF, SCC &C) {
1570-
Node &CGNode = get(NewF);
1571-
CGNode.DFSNumber = CGNode.LowLink = -1;
1572-
CGNode.populate();
1573-
C.Nodes.push_back(&CGNode);
1574-
SCCMap[&CGNode] = &C;
1575-
NodeMap[&NewF] = &CGNode;
1570+
addNodeToSCC(C, createNode(NewF));
1571+
}
1572+
1573+
void LazyCallGraph::addNewFunctionIntoRefSCC(Function &NewF, RefSCC &RC) {
1574+
Node &N = createNode(NewF);
1575+
1576+
auto *C = createSCC(RC, SmallVector<Node *, 1>());
1577+
addNodeToSCC(*C, N);
1578+
1579+
RC.SCCIndices[C] = RC.SCCIndices.size();
1580+
RC.SCCs.push_back(C);
15761581
}
15771582

15781583
LazyCallGraph::Node &LazyCallGraph::insertInto(Function &F, Node *&MappedN) {
@@ -1589,6 +1594,21 @@ void LazyCallGraph::updateGraphPtrs() {
15891594
RC->G = this;
15901595
}
15911596

1597+
LazyCallGraph::Node &LazyCallGraph::createNode(Function &F) {
1598+
assert(!lookup(F) && "node already exists");
1599+
1600+
Node &N = get(F);
1601+
NodeMap[&F] = &N;
1602+
N.DFSNumber = N.LowLink = -1;
1603+
N.populate();
1604+
return N;
1605+
}
1606+
1607+
void LazyCallGraph::addNodeToSCC(LazyCallGraph::SCC &C, Node &N) {
1608+
C.Nodes.push_back(&N);
1609+
SCCMap[&N] = &C;
1610+
}
1611+
15921612
template <typename RootsT, typename GetBeginT, typename GetEndT,
15931613
typename GetNodeT, typename FormSCCCallbackT>
15941614
void LazyCallGraph::buildGenericSCCs(RootsT &&Roots, GetBeginT &&GetBegin,

llvm/unittests/Analysis/CGSCCPassManagerTest.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1685,5 +1685,54 @@ TEST_F(CGSCCPassManagerTest, TestUpdateCGAndAnalysisManagerForPasses10) {
16851685
MPM.run(*M, MAM);
16861686
}
16871687

1688+
TEST_F(CGSCCPassManagerTest, TestInsertionOfNewRefSCC) {
1689+
std::unique_ptr<Module> M = parseIR("define void @f() {\n"
1690+
"entry:\n"
1691+
" call void @f()\n"
1692+
" ret void\n"
1693+
"}\n");
1694+
1695+
CGSCCPassManager CGPM(/*DebugLogging*/ true);
1696+
CGPM.addPass(LambdaSCCPassNoPreserve(
1697+
[&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG,
1698+
CGSCCUpdateResult &UR) {
1699+
for (auto &N : C) {
1700+
auto &F = N.getFunction();
1701+
if (F.getName() != "f")
1702+
continue;
1703+
auto *Call = dyn_cast<CallInst>(F.begin()->begin());
1704+
if (!Call || Call->getCalledFunction()->getName() != "f")
1705+
continue;
1706+
1707+
// Create a new function 'g'.
1708+
auto *G = Function::Create(F.getFunctionType(), F.getLinkage(),
1709+
F.getAddressSpace(), "g", F.getParent());
1710+
BasicBlock::Create(F.getParent()->getContext(), "entry", G);
1711+
// Instruct the LazyCallGraph to create a new node for 'g', as the
1712+
// single node in a new SCC, into the call graph. As a result
1713+
// the call graph is composed of a single RefSCC with two SCCs:
1714+
// [(f), (g)].
1715+
CG.addNewFunctionIntoRefSCC(*G, C.getOuterRefSCC());
1716+
1717+
// "Demote" the 'f -> f' call egde to a ref edge.
1718+
// 1. Erase the call edge from 'f' to 'f'.
1719+
Call->eraseFromParent();
1720+
// 2. Insert a ref edge from 'f' to 'f'.
1721+
(void)CastInst::CreatePointerCast(&F,
1722+
Type::getInt8PtrTy(F.getContext()),
1723+
"f.ref", &*F.begin()->begin());
1724+
1725+
ASSERT_NO_FATAL_FAILURE(
1726+
updateCGAndAnalysisManagerForCGSCCPass(CG, C, N, AM, UR))
1727+
<< "Updating the call graph with a demoted, self-referential "
1728+
"call edge 'f -> f', and a newly inserted ref edge 'f -> g', "
1729+
"caused a fatal failure";
1730+
}
1731+
}));
1732+
1733+
ModulePassManager MPM(/*DebugLogging*/ true);
1734+
MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
1735+
MPM.run(*M, MAM);
1736+
}
16881737
#endif
16891738
} // namespace

llvm/unittests/Analysis/LazyCallGraphTest.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2210,4 +2210,46 @@ TEST(LazyCallGraphTest, RemoveFunctionWithSpurriousRef) {
22102210
EXPECT_EQ(&RC2, &*I++);
22112211
EXPECT_EQ(CG.postorder_ref_scc_end(), I);
22122212
}
2213+
2214+
TEST(LazyCallGraphTest, AddNewFunctionIntoRefSCC) {
2215+
LLVMContext Context;
2216+
// Build and populate a graph composed of a single, self-referential node.
2217+
std::unique_ptr<Module> M = parseAssembly(Context, "define void @f() {\n"
2218+
"entry:\n"
2219+
" call void @f()\n"
2220+
" ret void\n"
2221+
"}\n");
2222+
LazyCallGraph CG = buildCG(*M);
2223+
CG.buildRefSCCs();
2224+
2225+
// At this point 'f' is in the call graph.
2226+
auto &F = lookupFunction(*M, "f");
2227+
LazyCallGraph::Node *FN = CG.lookup(F);
2228+
EXPECT_NE(FN, nullptr);
2229+
2230+
// And it has an SCC, of course.
2231+
auto *FSCC = CG.lookupSCC(*FN);
2232+
EXPECT_NE(FSCC, nullptr);
2233+
2234+
// Now, create a new function 'g'.
2235+
auto *G = Function::Create(F.getFunctionType(), F.getLinkage(),
2236+
F.getAddressSpace(), "g", F.getParent());
2237+
BasicBlock::Create(F.getParent()->getContext(), "entry", G);
2238+
2239+
// Instruct the LazyCallGraph to create a new node for 'g', within the same
2240+
// RefSCC as 'f', but in a separate SCC.
2241+
CG.addNewFunctionIntoRefSCC(*G, FSCC->getOuterRefSCC());
2242+
2243+
// 'g' should now be in the call graph.
2244+
LazyCallGraph::Node *GN = CG.lookup(*G);
2245+
EXPECT_NE(GN, nullptr);
2246+
// 'g' should have an SCC, composed of the singular node 'g'.
2247+
// ('f' should not be included in the 'g' SCC.)
2248+
LazyCallGraph::SCC *GSCC = CG.lookupSCC(*GN);
2249+
EXPECT_NE(GSCC, nullptr);
2250+
EXPECT_EQ(GSCC->size(), 1);
2251+
EXPECT_NE(GSCC, FSCC);
2252+
// 'g' and 'f' should be part of the same RefSCC.
2253+
EXPECT_EQ(&GSCC->getOuterRefSCC(), &FSCC->getOuterRefSCC());
2254+
}
22132255
}

0 commit comments

Comments
 (0)