// TODO: This only allows trivial edges to be added for now.
assert((RC == &TargetRC ||
RC->isAncestorOf(TargetRC)) && "New call edge is not trivial!");
- RC->insertTrivialCallEdge(N, *CallTarget);
+ // Add a trivial ref edge to be promoted later on alongside
+ // PromotedRefTargets.
+ RC->insertTrivialRefEdge(N, *CallTarget);
}
// Include synthetic reference edges to known, defined lib functions.
C, AM, UR);
}
+ // We added a ref edge earlier for new call edges, promote those to call edges
+ // alongside PromotedRefTargets.
+ for (Node *E : NewCallEdges)
+ PromotedRefTargets.insert(E);
+
// Now promote ref edges into call edges.
for (Node *CallTarget : PromotedRefTargets) {
SCC &TargetC = *G.lookupSCC(*CallTarget);
continue;
Changed = true;
- // Add all the inlined callees' edges as ref edges to the caller. These are
- // by definition trivial edges as we always have *some* transitive ref edge
- // chain. While in some cases these edges are direct calls inside the
- // callee, they have to be modeled in the inliner as reference edges as
- // there may be a reference edge anywhere along the chain from the current
- // caller to the callee that causes the whole thing to appear like
- // a (transitive) reference edge that will require promotion to a call edge
- // below.
- for (Function *InlinedCallee : InlinedCallees) {
- LazyCallGraph::Node &CalleeN = *CG.lookup(*InlinedCallee);
- for (LazyCallGraph::Edge &E : *CalleeN)
- RC->insertTrivialRefEdge(N, E.getNode());
- }
-
// At this point, since we have made changes we have at least removed
// a call instruction. However, in the process we do some incremental
// simplification of the surrounding code. This simplification can
// as we're going to mutate this particular function we want to make sure
// the proxy is in place to forward any invalidation events.
LazyCallGraph::SCC *OldC = C;
- C = &updateCGAndAnalysisManagerForFunctionPass(CG, *C, N, AM, UR, FAM);
+ C = &updateCGAndAnalysisManagerForCGSCCPass(CG, *C, N, AM, UR, FAM);
LLVM_DEBUG(dbgs() << "Updated inlining SCC: " << *C << "\n");
RC = &C->getOuterRefSCC();
MPM.run(*M, MAM);
}
+TEST_F(CGSCCPassManagerTest, TestInsertionOfNewNonTrivialCallEdge) {
+ std::unique_ptr<Module> M = parseIR("define void @f1() {\n"
+ "entry:\n"
+ " %a = bitcast void ()* @f4 to i8*\n"
+ " %b = bitcast void ()* @f2 to i8*\n"
+ " ret void\n"
+ "}\n"
+ "define void @f2() {\n"
+ "entry:\n"
+ " %a = bitcast void ()* @f1 to i8*\n"
+ " %b = bitcast void ()* @f3 to i8*\n"
+ " ret void\n"
+ "}\n"
+ "define void @f3() {\n"
+ "entry:\n"
+ " %a = bitcast void ()* @f2 to i8*\n"
+ " %b = bitcast void ()* @f4 to i8*\n"
+ " ret void\n"
+ "}\n"
+ "define void @f4() {\n"
+ "entry:\n"
+ " %a = bitcast void ()* @f3 to i8*\n"
+ " %b = bitcast void ()* @f1 to i8*\n"
+ " ret void\n"
+ "}\n");
+
+ bool Ran = false;
+ CGSCCPassManager CGPM(/*DebugLogging*/ true);
+ CGPM.addPass(LambdaSCCPassNoPreserve([&](LazyCallGraph::SCC &C,
+ CGSCCAnalysisManager &AM,
+ LazyCallGraph &CG,
+ CGSCCUpdateResult &UR) {
+ if (Ran)
+ return;
+
+ auto &FAM =
+ AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
+
+ for (auto &N : C) {
+ auto &F = N.getFunction();
+ if (F.getName() != "f1")
+ continue;
+
+ Function *F3 = F.getParent()->getFunction("f3");
+ ASSERT_TRUE(F3 != nullptr);
+
+ // Create call from f1 to f3.
+ (void)CallInst::Create(F3, {}, "", F.getEntryBlock().getTerminator());
+
+ ASSERT_NO_FATAL_FAILURE(
+ updateCGAndAnalysisManagerForCGSCCPass(CG, C, N, AM, UR, FAM))
+ << "Updating the call graph with mutually recursive g1 <-> g2, h1 "
+ "<-> h2 caused a fatal failure";
+
+ Ran = true;
+ }
+ }));
+
+ ModulePassManager MPM(/*DebugLogging*/ true);
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
+ MPM.run(*M, MAM);
+
+ ASSERT_TRUE(Ran);
+}
+
#endif
} // namespace