Skip to content

Commit 5e58c59

Browse files
committed
[LLVM][IPO] Add NoInlineFuncCalledOnce and plumb -no-inline-functions-called-once via PassBuilder
Signed-off-by: Karthikdhondi <[email protected]>
1 parent 32ff987 commit 5e58c59

File tree

4 files changed

+100
-0
lines changed

4 files changed

+100
-0
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#ifndef LLVM_TRANSFORMS_IPO_NOINLINEFUNCCALLEDONCE_H
2+
#define LLVM_TRANSFORMS_IPO_NOINLINEFUNCCALLEDONCE_H
3+
4+
#include "llvm/IR/PassManager.h"
5+
#include "llvm/Support/CommandLine.h"
6+
7+
namespace llvm {
8+
9+
struct NoInlineFuncCalledOncePass
10+
: public PassInfoMixin<NoInlineFuncCalledOncePass> {
11+
PreservedAnalyses run(Module &M, ModuleAnalysisManager &);
12+
};
13+
14+
// single definition of the control flag lives in the .cpp (declared here)
15+
extern cl::opt<bool> EnableNoInlineFuncCalledOnce;
16+
17+
} // namespace llvm
18+
#endif

llvm/lib/Passes/PassBuilderPipelines.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
#include "llvm/Transforms/IPO/MemProfContextDisambiguation.h"
6767
#include "llvm/Transforms/IPO/MergeFunctions.h"
6868
#include "llvm/Transforms/IPO/ModuleInliner.h"
69+
#include "llvm/Transforms/IPO/NoInlineFuncCalledOnce.h"
6970
#include "llvm/Transforms/IPO/OpenMPOpt.h"
7071
#include "llvm/Transforms/IPO/PartialInlining.h"
7172
#include "llvm/Transforms/IPO/SCCP.h"
@@ -150,6 +151,12 @@
150151

151152
using namespace llvm;
152153

154+
namespace llvm {
155+
cl::opt<bool> EnableNoInlineFuncCalledOnce(
156+
"no-inline-functions-called-once", cl::init(false), cl::Hidden,
157+
cl::desc("Mark TU-local functions called exactly once as noinline"));
158+
} // namespace llvm
159+
153160
static cl::opt<InliningAdvisorMode> UseInlineAdvisor(
154161
"enable-ml-inliner", cl::init(InliningAdvisorMode::Default), cl::Hidden,
155162
cl::desc("Enable ML policy for inliner. Currently trained for -Oz only"),
@@ -1274,6 +1281,9 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
12741281
PGOOpt->Action == PGOOptions::SampleUse))
12751282
MPM.addPass(PGOForceFunctionAttrsPass(PGOOpt->ColdOptType));
12761283

1284+
if (EnableNoInlineFuncCalledOnce)
1285+
MPM.addPass(NoInlineFuncCalledOncePass());
1286+
12771287
MPM.addPass(AlwaysInlinerPass(/*InsertLifetimeIntrinsics=*/true));
12781288

12791289
if (EnableModuleInliner)
@@ -1447,6 +1457,9 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level,
14471457
const bool LTOPreLink = isLTOPreLink(LTOPhase);
14481458
ModulePassManager MPM;
14491459

1460+
if (EnableNoInlineFuncCalledOnce)
1461+
MPM.addPass(NoInlineFuncCalledOncePass());
1462+
14501463
// Run partial inlining pass to partially inline functions that have
14511464
// large bodies.
14521465
if (RunPartialInlining)
@@ -1766,6 +1779,9 @@ PassBuilder::buildThinLTOPreLinkDefaultPipeline(OptimizationLevel Level) {
17661779
return MPM;
17671780
}
17681781

1782+
if (EnableNoInlineFuncCalledOnce)
1783+
MPM.addPass(NoInlineFuncCalledOncePass());
1784+
17691785
// Run partial inlining pass to partially inline functions that have
17701786
// large bodies.
17711787
// FIXME: It isn't clear whether this is really the right place to run this
@@ -2012,6 +2028,9 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
20122028
// Lower variadic functions for supported targets prior to inlining.
20132029
MPM.addPass(ExpandVariadicsPass(ExpandVariadicsMode::Optimize));
20142030

2031+
if (EnableNoInlineFuncCalledOnce)
2032+
MPM.addPass(NoInlineFuncCalledOncePass());
2033+
20152034
// Note: historically, the PruneEH pass was run first to deduce nounwind and
20162035
// generally clean up exception handling overhead. It isn't clear this is
20172036
// valuable as the inliner doesn't currently care whether it is inlining an

llvm/lib/Transforms/IPO/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ add_llvm_component_library(LLVMipo
3333
MemProfContextDisambiguation.cpp
3434
MergeFunctions.cpp
3535
ModuleInliner.cpp
36+
NoInlineFuncCalledOnce.cpp
3637
OpenMPOpt.cpp
3738
PartialInlining.cpp
3839
SampleContextTracker.cpp
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#include "llvm/Transforms/IPO/NoInlineFuncCalledOnce.h"
2+
#include "llvm/ADT/DenseMap.h"
3+
#include "llvm/ADT/DenseSet.h"
4+
#include "llvm/IR/Attributes.h"
5+
#include "llvm/IR/Function.h"
6+
#include "llvm/IR/InstIterator.h"
7+
#include "llvm/IR/Instructions.h"
8+
#include "llvm/IR/Module.h"
9+
#include "llvm/IR/PassManager.h"
10+
#include "llvm/Support/CommandLine.h"
11+
12+
using namespace llvm;
13+
14+
PreservedAnalyses NoInlineFuncCalledOncePass::run(Module &M,
15+
ModuleAnalysisManager &) {
16+
DenseMap<Function *, unsigned> DirectCalls;
17+
DenseSet<Function *> Recursive;
18+
19+
for (Function &F : M)
20+
if (!F.isDeclaration() && (F.hasInternalLinkage() || F.hasPrivateLinkage()))
21+
DirectCalls[&F] = 0;
22+
23+
for (Function &Caller : M) {
24+
if (Caller.isDeclaration())
25+
continue;
26+
for (Instruction &I : instructions(Caller)) {
27+
auto *CB = dyn_cast<CallBase>(&I);
28+
if (!CB)
29+
continue;
30+
const Value *Op = CB->getCalledOperand()->stripPointerCasts();
31+
if (auto *Callee = const_cast<Function *>(dyn_cast<Function>(Op))) {
32+
if (!DirectCalls.count(Callee))
33+
continue;
34+
DirectCalls[Callee] += 1;
35+
if (&Caller == Callee)
36+
Recursive.insert(Callee);
37+
}
38+
}
39+
}
40+
41+
bool Changed = false;
42+
for (auto &KV : DirectCalls) {
43+
Function *F = KV.first;
44+
unsigned N = KV.second;
45+
46+
if (N != 1)
47+
continue; // only called-once
48+
if (Recursive.count(F))
49+
continue; // skip recursion
50+
if (F->hasAddressTaken())
51+
continue; // skip address-taken
52+
if (F->hasFnAttribute(Attribute::AlwaysInline))
53+
continue;
54+
if (F->hasFnAttribute(Attribute::NoInline))
55+
continue;
56+
57+
F->addFnAttr(Attribute::NoInline);
58+
Changed = true;
59+
}
60+
61+
return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
62+
}

0 commit comments

Comments
 (0)