1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

[CGSCC][Inliner] Handle new non-trivial edges in updateCGAndAnalysisManagerForPass

Previously the inliner did a bit of a hack by adding ref edges for all
new edges introduced by performing an inline before calling
updateCGAndAnalysisManagerForPass(). This was because
updateCGAndAnalysisManagerForPass() didn't handle new non-trivial call
edges.

This adds handling of non-trivial call edges to
updateCGAndAnalysisManagerForPass().  The inliner called
updateCGAndAnalysisManagerForFunctionPass() since it was handling adding
newly introduced edges (so updateCGAndAnalysisManagerForPass() would
only have to handle promotion), but now it needs to call
updateCGAndAnalysisManagerForCGSCCPass() since
updateCGAndAnalysisManagerForPass() is now handling the new call edges
and function passes cannot add new edges.

We follow the previous path of adding trivial ref edges then letting promotion
handle changing the ref edges to call edges and the CGSCC updates. So
this still does not allow adding call edges that result in an addition
of a non-trivial ref edge.

This is in preparation for better detecting devirtualization. Previously
since the inliner itself would add ref edges,
updateCGAndAnalysisManagerForPass() would think that promotion and thus
devirtualization had happened after any sort of inlining.

Reviewed By: asbirlea

Differential Revision: https://reviews.llvm.org/D91046
This commit is contained in:
Arthur Eubanks 2020-11-06 18:32:46 -08:00
parent 3ff178e54c
commit ce3fe31482
3 changed files with 74 additions and 16 deletions

View File

@ -549,7 +549,9 @@ static LazyCallGraph::SCC &updateCGAndAnalysisManagerForPass(
// 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.
@ -664,6 +666,11 @@ static LazyCallGraph::SCC &updateCGAndAnalysisManagerForPass(
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);

View File

@ -933,20 +933,6 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
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
@ -959,7 +945,7 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
// 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();

View File

@ -1838,5 +1838,70 @@ TEST_F(CGSCCPassManagerTest, TestInsertionOfNewRefSCCMutuallyRecursive) {
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