[PATCH] D145516: [Inliner] Avoid excessive inlining through devirtualised calls
Arthur Eubanks via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 17 13:03:58 PDT 2023
aeubanks added a comment.
apologies, was out on vacation for a while
================
Comment at: llvm/lib/Transforms/IPO/Inliner.cpp:974-975
+ CalleeSCC != CG.lookupSCC(CG.get(*NewCallee))) {
+ // This newly devirtualised function call might form a cycle in
+ // our RefSCC, don't repeatedly inline it as mentioned above.
+ // Take the cost multiplier from the new call-site function:
----------------
IIUC, there's never actually a cycle (ref or call) in the IR. The problem is that after inlining, we do see the same sort of issue as with inlining through a child SCC because the indirect calls end up ping ponging between `@longname` and `@rec_call_to_longname`.
================
Comment at: llvm/lib/Transforms/IPO/Inliner.cpp:976-980
+ // Take the cost multiplier from the new call-site function:
+ // we do not get the SCC-post-order traversal guarantee as
+ // NewCallee is in a different SCC, thus a different SCCs
+ // inlining NewCallee might give it different multipliers each
+ // time.
----------------
I don't understand this comment. I tried the following diff and it adds the multiplier attributes as expected
```
@@ -418,8 +420,15 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
// inline through the SCC the function will end up being
// self-recursive which the inliner bails out on, and inlining
// within an SCC is necessary for performance.
- if (CalleeSCC != C &&
- CalleeSCC == CG.lookupSCC(CG.get(*NewCallee))) {
+ auto WasCallEdge = [&CG](Function &Callee, Function &NewCallee) {
+ LazyCallGraph::Node &CalleeN = CG.get(Callee);
+ LazyCallGraph::Node &NewCalleeN = CG.get(NewCallee);
+ LazyCallGraph::Edge *E = CalleeN->lookup(NewCalleeN);
+ return E && E->isCall();
+ };
+ if ((CalleeSCC != C &&
+ CalleeSCC == CG.lookupSCC(CG.get(*NewCallee))) ||
+ !WasCallEdge(Callee, *NewCallee)) {
Attribute NewCBCostMult = Attribute::get(
M.getContext(),
InlineConstants::FunctionInlineCostMultiplierAttributeName,
```
================
Comment at: llvm/lib/Transforms/IPO/Inliner.cpp:989
+ InlineConstants::FunctionInlineCostMultiplierAttributeName,
+ itostr(std::min(CBCostMult * IntraSCCCostMultiplier, 10000)));
+ NewCallee->addFnAttr(NewCBCostMult);
----------------
what's the 10000 for, can we reuse the existing code?
================
Comment at: llvm/test/Transforms/Inline/devirtualize-7.ll:1
+; RUN: opt %s -o - --passes='cgscc(inline)' -S | FileCheck %s --implicit-check-not=@extern2
+
----------------
slightly reduced test case
```
target triple = "x86_64-unknown-unknown"
declare void @extern1()
define internal void @rec_call_to_longname(ptr %longname) {
call void %longname(ptr @rec_call_to_longname)
ret void
}
define internal void @longname(ptr %0) {
call void @extern1()
call void @extern1()
call void @extern1()
call void %0(ptr @longname) ; Exponential growth occurs between these two devirt calls.
call void %0(ptr @longname)
ret void
}
define void @e() {
call void @c()
call void @c()
ret void
}
define internal void @c() {
call void @b()
ret void
}
define internal void @b() {
call void @a()
ret void
}
define internal void @a() {
call void @rec_call_to_longname(ptr @longname)
ret void
}
```
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D145516/new/
https://reviews.llvm.org/D145516
More information about the llvm-commits
mailing list