[llvm] e19a5fc - [FuncSpec] Improve accounting of specialization codesize growth (#113448)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Oct 29 04:53:16 PDT 2024
Author: Hari Limaye
Date: 2024-10-29T11:53:12Z
New Revision: e19a5fc6d306a81d181a9597a8b25c444c08d722
URL: https://github.com/llvm/llvm-project/commit/e19a5fc6d306a81d181a9597a8b25c444c08d722
DIFF: https://github.com/llvm/llvm-project/commit/e19a5fc6d306a81d181a9597a8b25c444c08d722.diff
LOG: [FuncSpec] Improve accounting of specialization codesize growth (#113448)
Only accumulate the codesize increase of functions that are actually
specialized, rather than for every candidate specialization that we
analyse.
This fixes a subtle bug where prior analysis of candidate
specializations that were deemed unprofitable could prevent subsequent
profitable candidates from being recognised.
Added:
llvm/test/Transforms/FunctionSpecialization/maxgrowth.ll
Modified:
llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h
llvm/lib/Transforms/IPO/FunctionSpecialization.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h b/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h
index f20b01c186306d..e82155a6c72974 100644
--- a/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h
+++ b/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h
@@ -138,13 +138,16 @@ struct Spec {
// Profitability of the specialization.
unsigned Score;
+ // Number of instructions in the specialization.
+ unsigned CodeSize;
+
// List of call sites, matching this specialization.
SmallVector<CallBase *> CallSites;
- Spec(Function *F, const SpecSig &S, unsigned Score)
- : F(F), Sig(S), Score(Score) {}
- Spec(Function *F, const SpecSig &&S, unsigned Score)
- : F(F), Sig(S), Score(Score) {}
+ Spec(Function *F, const SpecSig &S, unsigned Score, unsigned CodeSize)
+ : F(F), Sig(S), Score(Score), CodeSize(CodeSize) {}
+ Spec(Function *F, const SpecSig &&S, unsigned Score, unsigned CodeSize)
+ : F(F), Sig(S), Score(Score), CodeSize(CodeSize) {}
};
class InstCostVisitor : public InstVisitor<InstCostVisitor, Constant *> {
diff --git a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp
index 8e6993d35d4991..919d3143a13f7e 100644
--- a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp
@@ -643,6 +643,18 @@ FunctionSpecializer::~FunctionSpecializer() {
cleanUpSSA();
}
+/// Get the unsigned Value of given Cost object. Assumes the Cost is always
+/// non-negative, which is true for both TCK_CodeSize and TCK_Latency, and
+/// always Valid.
+static unsigned getCostValue(const Cost &C) {
+ int64_t Value = *C.getValue();
+
+ assert(Value >= 0 && "CodeSize and Latency cannot be negative");
+ // It is safe to down cast since we know the arguments cannot be negative and
+ // Cost is of type int64_t.
+ return static_cast<unsigned>(Value);
+}
+
/// Attempt to specialize functions in the module to enable constant
/// propagation across function boundaries.
///
@@ -757,6 +769,11 @@ bool FunctionSpecializer::run() {
SmallVector<Function *> Clones;
for (unsigned I = 0; I < NSpecs; ++I) {
Spec &S = AllSpecs[BestSpecs[I]];
+
+ // Accumulate the codesize growth for the function, now we are creating the
+ // specialization.
+ FunctionGrowth[S.F] += S.CodeSize;
+
S.Clone = createSpecialization(S.F, S.Sig);
// Update the known call sites to call the clone.
@@ -835,18 +852,6 @@ static Function *cloneCandidateFunction(Function *F, unsigned NSpecs) {
return Clone;
}
-/// Get the unsigned Value of given Cost object. Assumes the Cost is always
-/// non-negative, which is true for both TCK_CodeSize and TCK_Latency, and
-/// always Valid.
-static unsigned getCostValue(const Cost &C) {
- int64_t Value = *C.getValue();
-
- assert(Value >= 0 && "CodeSize and Latency cannot be negative");
- // It is safe to down cast since we know the arguments cannot be negative and
- // Cost is of type int64_t.
- return static_cast<unsigned>(Value);
-}
-
bool FunctionSpecializer::findSpecializations(Function *F, unsigned FuncSize,
SmallVectorImpl<Spec> &AllSpecs,
SpecMap &SM) {
@@ -922,16 +927,14 @@ bool FunctionSpecializer::findSpecializations(Function *F, unsigned FuncSize,
}
CodeSize += Visitor.getCodeSizeSavingsFromPendingPHIs();
+ unsigned CodeSizeSavings = getCostValue(CodeSize);
+ unsigned SpecSize = FuncSize - CodeSizeSavings;
+
auto IsProfitable = [&]() -> bool {
// No check required.
if (ForceSpecialization)
return true;
- unsigned CodeSizeSavings = getCostValue(CodeSize);
- // TODO: We should only accumulate codesize increase of specializations
- // that are actually created.
- FunctionGrowth[F] += FuncSize - CodeSizeSavings;
-
LLVM_DEBUG(
dbgs() << "FnSpecialization: Specialization bonus {Inlining = "
<< Score << " (" << (Score * 100 / FuncSize) << "%)}\n");
@@ -962,7 +965,7 @@ bool FunctionSpecializer::findSpecializations(Function *F, unsigned FuncSize,
if (LatencySavings < MinLatencySavings * FuncSize / 100)
return false;
// Maximum codesize growth.
- if (FunctionGrowth[F] / FuncSize > MaxCodeSizeGrowth)
+ if ((FunctionGrowth[F] + SpecSize) / FuncSize > MaxCodeSizeGrowth)
return false;
Score += std::max(CodeSizeSavings, LatencySavings);
@@ -974,7 +977,7 @@ bool FunctionSpecializer::findSpecializations(Function *F, unsigned FuncSize,
continue;
// Create a new specialisation entry.
- auto &Spec = AllSpecs.emplace_back(F, S, Score);
+ auto &Spec = AllSpecs.emplace_back(F, S, Score, SpecSize);
if (CS.getFunction() != F)
Spec.CallSites.push_back(&CS);
const unsigned Index = AllSpecs.size() - 1;
diff --git a/llvm/test/Transforms/FunctionSpecialization/maxgrowth.ll b/llvm/test/Transforms/FunctionSpecialization/maxgrowth.ll
new file mode 100644
index 00000000000000..82d1f7ae4a6e16
--- /dev/null
+++ b/llvm/test/Transforms/FunctionSpecialization/maxgrowth.ll
@@ -0,0 +1,44 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs --version 5
+; RUN: opt -passes="ipsccp<func-spec>" -funcspec-min-function-size=1 \
+; RUN: -funcspec-for-literal-constant=true \
+; RUN: -funcspec-min-codesize-savings=50 \
+; RUN: -funcspec-min-latency-savings=50 \
+; RUN: -funcspec-max-codesize-growth=1 \
+; RUN: -S < %s | FileCheck %s
+
+; Verify that we are able to specialize a function successfully after analysis
+; of other specializations that are found to not be profitable.
+define void @test_specialize_after_failed_analysis(i32 %n) {
+entry:
+ %notspec0 = call i32 @add(i32 0, i32 %n)
+ %notspec1 = call i32 @add(i32 1, i32 %n)
+ %spec = call i32 @add(i32 1, i32 1)
+ ret void
+}
+
+define i32 @add(i32 %x, i32 %y) {
+entry:
+ %res = add i32 %x, %y
+ ret i32 %res
+}
+; CHECK-LABEL: define void @test_specialize_after_failed_analysis(
+; CHECK-SAME: i32 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[NOTSPEC0:%.*]] = call i32 @add(i32 0, i32 [[N]])
+; CHECK-NEXT: [[NOTSPEC1:%.*]] = call i32 @add(i32 1, i32 [[N]])
+; CHECK-NEXT: [[SPEC:%.*]] = call i32 @add.specialized.1(i32 1, i32 1)
+; CHECK-NEXT: ret void
+;
+;
+; CHECK-LABEL: define i32 @add(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[RES:%.*]] = add i32 [[X]], [[Y]]
+; CHECK-NEXT: ret i32 [[RES]]
+;
+;
+; CHECK-LABEL: define internal i32 @add.specialized.1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: ret i32 poison
+;
More information about the llvm-commits
mailing list