Skip to content

[SILOptimizer] Expose SIL inliner heuristics/constants as -Xllvm configurable knobs #80914

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 30, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 100 additions & 71 deletions lib/SILOptimizer/Transforms/PerformanceInliner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,104 @@ llvm::cl::opt<bool> EnableVerifyAfterEachInlining(
"Run sil verification after inlining each found callee apply "
"site into a caller."));

//===----------------------------------------------------------------------===//
// Heuristics
//===----------------------------------------------------------------------===//

/// The following constants define the cost model for inlining. Some constants
/// are also defined in ShortestPathAnalysis.

llvm::cl::opt<int> RemovedCallBenefit(
"sil-inline-removed-call-benefit", llvm::cl::init(20),
llvm::cl::desc("The base value for every call: it represents the benefit "
"of removing the call overhead itself."));

llvm::cl::opt<int> RemovedCoroutineCallBenefit(
"sil-inline-removed-coroutine-call-benefit", llvm::cl::init(300),
llvm::cl::desc("The benefit of inlining a `begin_apply`."));

llvm::cl::opt<int> RemovedClosureBenefit(
"sil-inline-removed-closure-benefit",
llvm::cl::init(RemovedCallBenefit + 50),
llvm::cl::desc(
"The benefit if the operand of an apply gets constant e.g. if a "
"closure is passed to an apply instruction in the callee."));

llvm::cl::opt<int> RemovedLoadBenefit(
"sil-inline-removed-load-benefit", llvm::cl::init(RemovedCallBenefit + 5),
llvm::cl::desc("The benefit if a load can (probably) eliminated because it "
"loads from a stack location in the caller."));

llvm::cl::opt<int> RemovedStoreBenefit(
"sil-inline-removed-store-benefit", llvm::cl::init(RemovedCallBenefit + 10),
llvm::cl::desc("The benefit if a store can (probably) eliminated because "
"it stores to a stack location in the caller."));

llvm::cl::opt<int> RemovedTerminatorBenefit(
"sil-inline-removed-terminator-benefit",
llvm::cl::init(RemovedCallBenefit + 10),
llvm::cl::desc("The benefit if the condition of a terminator instruction "
"gets constant due to inlining."));

llvm::cl::opt<int>
RefCountBenefit("sil-inline-ref-count-benefit",
llvm::cl::init(RemovedCallBenefit + 20),
llvm::cl::desc("The benefit if a retain/release can "
"(probably) be eliminated after inlining."));

llvm::cl::opt<int> FastPathBuiltinBenefit(
"sil-inline-fast-path-builtin-benefit",
llvm::cl::init(RemovedCallBenefit + 40),
llvm::cl::desc("The benefit of a onFastPath builtin."));

llvm::cl::opt<int> DevirtualizedCallBenefit(
"sil-inline-devirtualized-call-benefit",
llvm::cl::init(RemovedCallBenefit + 300),
llvm::cl::desc("The benefit of being able to devirtualize a call."));

llvm::cl::opt<int> GenericSpecializationBenefit(
"sil-inline-generic-specialization-benefit",
llvm::cl::init(RemovedCallBenefit + 300),
llvm::cl::desc("The benefit of being able to produce a generic "
"specialization for a call."));

llvm::cl::opt<int> ExclusivityBenefit(
"sil-inline-exclusivity-benefit", llvm::cl::init(RemovedCallBenefit + 10),
llvm::cl::desc("The benefit of inlining an exclusivity-containing callee. "
"The exclusivity needs to be: dynamic, has no nested "
"conflict and addresses known storage"));

llvm::cl::opt<int> OSizeClassMethodBenefit(
"sil-inline-o-size-class-method-benefit", llvm::cl::init(5),
llvm::cl::desc("The benefit of inlining class methods with -Osize. We only "
"inline very small class methods with -Osize."));

llvm::cl::opt<int> TrivialFunctionThreshold(
"sil-inline-trivial-function-threshold", llvm::cl::init(18),
llvm::cl::desc("Approximately up to this cost level a function can be "
"inlined without increasing the code size."));

llvm::cl::opt<int> BlockLimitDenominator(
"sil-inline-block-limit-denominator", llvm::cl::init(3000),
llvm::cl::desc("Configuration for the \"soft\" caller block limit. When "
"changing make sure you update BlockLimitMaxIntNumerator."));

llvm::cl::opt<int> BlockLimitMaxIntNumerator(
"sil-inline-block-limit-max-int-numerator", llvm::cl::init(18608),
llvm::cl::desc("Computations with BlockLimitDenominator will overflow with "
"numerators >= this value. This equals cbrt(INT_MAX) * "
"cbrt(BlockLimitDenominator); we hardcode its value because "
"std::cbrt() is not constexpr."));

llvm::cl::opt<int> OverallCallerBlockLimit(
"sil-inline-overall-caller-block-limit", llvm::cl::init(400),
llvm::cl::desc("No inlining is done if the caller has more than this "
"number of blocks."));

llvm::cl::opt<int> DefaultApplyLength(
"sil-inline-default-apply-length", llvm::cl::init(10),
llvm::cl::desc("The assumed execution length of a function call."));

//===----------------------------------------------------------------------===//
// Printing Helpers
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -118,75 +216,6 @@ class SILPerformanceInliner {

OptRemark::Emitter &ORE;

/// The following constants define the cost model for inlining. Some constants
/// are also defined in ShortestPathAnalysis.
enum {
/// The base value for every call: it represents the benefit of removing the
/// call overhead itself.
RemovedCallBenefit = 20,

/// The benefit of inlining a `begin_apply`.
RemovedCoroutineCallBenefit = 300,

/// The benefit if the operand of an apply gets constant, e.g. if a closure
/// is passed to an apply instruction in the callee.
RemovedClosureBenefit = RemovedCallBenefit + 50,

/// The benefit if a load can (probably) eliminated because it loads from
/// a stack location in the caller.
RemovedLoadBenefit = RemovedCallBenefit + 5,

/// The benefit if a store can (probably) eliminated because it stores to
/// a stack location in the caller.
RemovedStoreBenefit = RemovedCallBenefit + 10,

/// The benefit if the condition of a terminator instruction gets constant
/// due to inlining.
RemovedTerminatorBenefit = RemovedCallBenefit + 10,

/// The benefit if a retain/release can (probably) be eliminated after
/// inlining.
RefCountBenefit = RemovedCallBenefit + 20,

/// The benefit of a onFastPath builtin.
FastPathBuiltinBenefit = RemovedCallBenefit + 40,

/// The benefit of being able to devirtualize a call.
DevirtualizedCallBenefit = RemovedCallBenefit + 300,

/// The benefit of being able to produce a generic
/// specialization for a call.
GenericSpecializationBenefit = RemovedCallBenefit + 300,

/// The benefit of inlining an exclusivity-containing callee.
/// The exclusivity needs to be: dynamic,
/// has no nested conflict and addresses known storage
ExclusivityBenefit = RemovedCallBenefit + 10,

/// The benefit of inlining class methods with -Osize.
/// We only inline very small class methods with -Osize.
OSizeClassMethodBenefit = 5,

/// Approximately up to this cost level a function can be inlined without
/// increasing the code size.
TrivialFunctionThreshold = 18,

/// Configuration for the "soft" caller block limit. When changing, make
/// sure you update BlockLimitMaxIntNumerator.
BlockLimitDenominator = 3000,

/// Computations with BlockLimitDenominator will overflow with numerators
/// >= this value. This equals cbrt(INT_MAX) * cbrt(BlockLimitDenominator);
/// we hardcode its value because std::cbrt() is not constexpr.
BlockLimitMaxIntNumerator = 18608,

/// No inlining is done if the caller has more than this number of blocks.
OverallCallerBlockLimit = 400,

/// The assumed execution length of a function call.
DefaultApplyLength = 10
};

OptimizationMode OptMode;

#ifndef NDEBUG
Expand Down Expand Up @@ -577,7 +606,7 @@ bool SILPerformanceInliner::isProfitableToInline(
CalleeSPA->analyze(CBI, [](FullApplySite FAS) {
// We don't compute SPA for another call-level. Functions called from
// the callee are assumed to have DefaultApplyLength.
return DefaultApplyLength;
return DefaultApplyLength.getValue();
});
}

Expand Down Expand Up @@ -1129,7 +1158,7 @@ void SILPerformanceInliner::collectAppliesToInline(
CalleeSPA->analyze(CBI, [](FullApplySite FAS) {
// We don't compute SPA for another call-level. Functions called from
// the callee are assumed to have DefaultApplyLength.
return DefaultApplyLength;
return DefaultApplyLength.getValue();
});
}
int CalleeLength = CalleeSPA->getScopeLength(&Callee->front(), 0);
Expand Down