Skip to content

Commit

Permalink
[CSSPGO] Allow inlining recursive call for preinliner
Browse files Browse the repository at this point in the history
When preinliner is used for CSSPGO, we try to honor global preinliner decision as much as we can except for uninlinable callees. We rely on InlineCost::Never to prevent us from illegal inlining.

However, it turns out that we use InlineCost::Never for both illeagle inlining and some of the "not-so-beneficial" inlining.

The most common one is recursive inlining, while it can bloat size a lot during CGSCC bottom-up inlining, it's less of a problem when recursive inlining is guided by profile and done in top-down manner.

Ideally it'd be better to have a clear separation between inline legality check vs cost-benefit check, but that requires a bigger change.

This change enables InlineCost computation to allow inlining recursive calls, controlled by InlineParams. In SampleLoader, we now enable recursive inlining for CSSPGO when global preinliner decision is used.

With this change, we saw a few perf improvements on SPEC2017 with CSSPGO and preinliner on: 2% for povray_r, 6% for xalancbmk_s, 3% omnetpp_s, while size is about the same (no noticeable perf change for all other benchmarks)

Differential Revision: https://reviews.llvm.org/D109104
  • Loading branch information
WenleiHe committed Sep 2, 2021
1 parent c86e1ce commit f7fff46
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 4 deletions.
3 changes: 3 additions & 0 deletions llvm/include/llvm/Analysis/InlineCost.h
Expand Up @@ -213,6 +213,9 @@ struct InlineParams {

/// Indicate whether we should allow inline deferral.
Optional<bool> EnableDeferral = true;

/// Indicate whether we allow inlining for recursive call.
Optional<bool> AllowRecursiveCall = false;
};

/// Generate the parameters to tune the inline cost analysis based only on the
Expand Down
16 changes: 12 additions & 4 deletions llvm/lib/Analysis/InlineCost.cpp
Expand Up @@ -362,6 +362,10 @@ class CallAnalyzer : public InstVisitor<CallAnalyzer, bool> {
/// whenever we simplify away the stores that would otherwise cause them to be
/// loads.
bool EnableLoadElimination;

/// Whether we allow inlining for recursive call.
bool AllowRecursiveCall;

SmallPtrSet<Value *, 16> LoadAddrSet;

AllocaInst *getSROAArgForValueOrNull(Value *V) const {
Expand Down Expand Up @@ -450,7 +454,8 @@ class CallAnalyzer : public InstVisitor<CallAnalyzer, bool> {
OptimizationRemarkEmitter *ORE = nullptr)
: TTI(TTI), GetAssumptionCache(GetAssumptionCache), GetBFI(GetBFI),
PSI(PSI), F(Callee), DL(F.getParent()->getDataLayout()), ORE(ORE),
CandidateCall(Call), EnableLoadElimination(true) {}
CandidateCall(Call), EnableLoadElimination(true),
AllowRecursiveCall(false) {}

InlineResult analyze();

Expand Down Expand Up @@ -983,7 +988,9 @@ class InlineCostCallAnalyzer final : public CallAnalyzer {
Params(Params), Threshold(Params.DefaultThreshold),
BoostIndirectCalls(BoostIndirect), IgnoreThreshold(IgnoreThreshold),
CostBenefitAnalysisEnabled(isCostBenefitAnalysisEnabled()),
Writer(this) {}
Writer(this) {
AllowRecursiveCall = Params.AllowRecursiveCall.getValue();
}

/// Annotation Writer for instruction details
InlineCostAnnotationWriter Writer;
Expand Down Expand Up @@ -2154,7 +2161,8 @@ bool CallAnalyzer::visitCallBase(CallBase &Call) {
// This flag will fully abort the analysis, so don't bother with anything
// else.
IsRecursiveCall = true;
return false;
if (!AllowRecursiveCall)
return false;
}

if (TTI.isLoweredToCall(F)) {
Expand Down Expand Up @@ -2392,7 +2400,7 @@ CallAnalyzer::analyzeBlock(BasicBlock *BB,
using namespace ore;
// If the visit this instruction detected an uninlinable pattern, abort.
InlineResult IR = InlineResult::success();
if (IsRecursiveCall)
if (IsRecursiveCall && !AllowRecursiveCall)
IR = InlineResult::failure("recursive");
else if (ExposesReturnsTwice)
IR = InlineResult::failure("exposes returns twice");
Expand Down
11 changes: 11 additions & 0 deletions llvm/lib/Transforms/IPO/SampleProfile.cpp
Expand Up @@ -219,6 +219,11 @@ static cl::opt<bool> UsePreInlinerDecision(
cl::init(false),
cl::desc("Use the preinliner decisions stored in profile context."));

static cl::opt<bool> AllowRecursiveInline(
"sample-profile-recursive-inline", cl::Hidden, cl::ZeroOrMore,
cl::init(false),
cl::desc("Allow sample loader inliner to inline recursive calls."));

static cl::opt<std::string> ProfileInlineReplayFile(
"sample-profile-inline-replay", cl::init(""), cl::value_desc("filename"),
cl::desc(
Expand Down Expand Up @@ -1283,7 +1288,9 @@ SampleProfileLoader::shouldInlineCandidate(InlineCandidate &Candidate) {
assert(Callee && "Expect a definition for inline candidate of direct call");

InlineParams Params = getInlineParams();
// We will ignore the threshold from inline cost, so always get full cost.
Params.ComputeFullInlineCost = true;
Params.AllowRecursiveCall = AllowRecursiveInline;
// Checks if there is anything in the reachable portion of the callee at
// this callsite that makes this inlining potentially illegal. Need to
// set ComputeFullInlineCost, otherwise getInlineCost may return early
Expand Down Expand Up @@ -1840,6 +1847,10 @@ bool SampleProfileLoader::doInitialization(Module &M,
if (!UsePreInlinerDecision.getNumOccurrences())
UsePreInlinerDecision = true;

// For CSSPGO, we also allow recursive inline to best use context profile.
if (!AllowRecursiveInline.getNumOccurrences())
AllowRecursiveInline = true;

// Enable iterative-BFI by default for CSSPGO.
if (!UseIterativeBFIInference.getNumOccurrences())
UseIterativeBFIInference = true;
Expand Down

0 comments on commit f7fff46

Please sign in to comment.