Skip to content

Commit c662103

Browse files
authored
[Coroutines][LazyCallGraph] addSplitRefRecursiveFunctions allows spurious ref edges between new functions. (#116285)
The addSplitRefRecursiveFunctions LazyCallGraph helper should not require a reference between every new function. Spurious ref edges between the new functions are allowed and the new function are considered to be a RefSCC. This change clarifies that this is the case in the method's description and its DEBUG mode verifier.
1 parent dcfc30c commit c662103

File tree

3 files changed

+67
-6
lines changed

3 files changed

+67
-6
lines changed

llvm/include/llvm/Analysis/LazyCallGraph.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,11 +1082,16 @@ class LazyCallGraph {
10821082
/// Add new ref-recursive functions split/outlined from an existing function.
10831083
///
10841084
/// The new functions may only reference other functions that the original
1085-
/// function did. The new functions may reference (not call) the original
1086-
/// function.
1085+
/// function did. The new functions may reference the original function. New
1086+
/// functions must not call other new functions or the original function.
10871087
///
1088-
/// The original function must reference (not call) all new functions.
1089-
/// All new functions must reference (not call) each other.
1088+
/// Marks the original function as referencing all new functions.
1089+
///
1090+
/// It is not necessary for each new function to reference all other new
1091+
/// functions. Spurious/missing ref edges are allowed. The new functions
1092+
/// are considered to be a RefSCC. If any new function references the
1093+
/// original function they are all considered to be part of the original
1094+
/// function's RefSCC.
10901095
void addSplitRefRecursiveFunctions(Function &OriginalFunction,
10911096
ArrayRef<Function *> NewFunctions);
10921097

llvm/lib/Analysis/LazyCallGraph.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1720,6 +1720,7 @@ void LazyCallGraph::addSplitRefRecursiveFunctions(
17201720
for (Function *NewFunction : NewFunctions) {
17211721
Node &NewN = initNode(*NewFunction);
17221722

1723+
// Make the original function reference each new function
17231724
OriginalN->insertEdgeInternal(NewN, Edge::Kind::Ref);
17241725

17251726
// Check if there is any edge from any new function back to any function in
@@ -1775,8 +1776,9 @@ void LazyCallGraph::addSplitRefRecursiveFunctions(
17751776
if (F1 == F2)
17761777
continue;
17771778
Node &N2 = get(*F2);
1778-
assert(!N1->lookup(N2)->isCall() &&
1779-
"Edges between new functions must be ref edges");
1779+
assert(!N1->lookup(N2) ||
1780+
(!N1->lookup(N2)->isCall() &&
1781+
"Edges between new functions must be ref edges"));
17801782
}
17811783
}
17821784
#endif

llvm/unittests/Analysis/LazyCallGraphTest.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3027,4 +3027,58 @@ TEST(LazyCallGraphTest, AddSplitFunctions5) {
30273027
EXPECT_EQ(RC, CG.lookupRefSCC(F2N));
30283028
EXPECT_EQ(CG.postorder_ref_scc_end(), I);
30293029
}
3030+
3031+
TEST(LazyCallGraphTest, AddSplitFunctions6) {
3032+
LLVMContext Context;
3033+
std::unique_ptr<Module> M = parseAssembly(Context, "define void @f() {\n"
3034+
" ret void\n"
3035+
"}\n");
3036+
LazyCallGraph CG = buildCG(*M);
3037+
3038+
Function &F = lookupFunction(*M, "f");
3039+
LazyCallGraph::Node &FN = CG.get(F);
3040+
3041+
// Force the graph to be fully expanded.
3042+
CG.buildRefSCCs();
3043+
auto I = CG.postorder_ref_scc_begin();
3044+
LazyCallGraph::RefSCC *ORC = &*I++;
3045+
EXPECT_EQ(CG.postorder_ref_scc_end(), I);
3046+
3047+
auto *G1 = Function::Create(F.getFunctionType(), F.getLinkage(),
3048+
F.getAddressSpace(), "g1", F.getParent());
3049+
auto *G2 = Function::Create(F.getFunctionType(), F.getLinkage(),
3050+
F.getAddressSpace(), "g2", F.getParent());
3051+
BasicBlock *G1BB = BasicBlock::Create(Context, "", G1);
3052+
BasicBlock *G2BB = BasicBlock::Create(Context, "", G2);
3053+
// Create g1 -ref-> g2 and g2 has no references.
3054+
(void)CastInst::CreatePointerCast(G2, PointerType::getUnqual(Context), "",
3055+
G1BB);
3056+
(void)ReturnInst::Create(Context, G1BB);
3057+
(void)ReturnInst::Create(Context, G2BB);
3058+
3059+
// Create f -ref-> g1 and f -ref-> g2.
3060+
(void)CastInst::CreatePointerCast(G1, PointerType::getUnqual(Context), "",
3061+
F.getEntryBlock().begin());
3062+
(void)CastInst::CreatePointerCast(G2, PointerType::getUnqual(Context), "",
3063+
F.getEntryBlock().begin());
3064+
3065+
EXPECT_FALSE(verifyModule(*M, &errs()));
3066+
3067+
CG.addSplitRefRecursiveFunctions(F, SmallVector<Function *, 1>({G1, G2}));
3068+
3069+
LazyCallGraph::Node *G1N = CG.lookup(*G1);
3070+
EXPECT_TRUE(G1N);
3071+
LazyCallGraph::Node *G2N = CG.lookup(*G2);
3072+
EXPECT_TRUE(G2N);
3073+
3074+
I = CG.postorder_ref_scc_begin();
3075+
LazyCallGraph::RefSCC *RC1 = &*I++;
3076+
EXPECT_EQ(2, RC1->size());
3077+
EXPECT_EQ(RC1, CG.lookupRefSCC(*G1N));
3078+
EXPECT_EQ(RC1, CG.lookupRefSCC(*G2N));
3079+
LazyCallGraph::RefSCC *RC2 = &*I++;
3080+
EXPECT_EQ(RC2, ORC);
3081+
EXPECT_EQ(RC2, CG.lookupRefSCC(FN));
3082+
EXPECT_EQ(CG.postorder_ref_scc_end(), I);
3083+
}
30303084
}

0 commit comments

Comments
 (0)