[llvm] 2c8a4c6 - Revert "[FuncSpec][NFC] Refactor finding specialisation opportunities"
Momchil Velikov via llvm-commits
llvm-commits at lists.llvm.org
Wed Oct 26 05:54:35 PDT 2022
Author: Momchil Velikov
Date: 2022-10-26T13:54:12+01:00
New Revision: 2c8a4c6e620cfcc45ebe7986503bfef3ebd6baca
URL: https://github.com/llvm/llvm-project/commit/2c8a4c6e620cfcc45ebe7986503bfef3ebd6baca
DIFF: https://github.com/llvm/llvm-project/commit/2c8a4c6e620cfcc45ebe7986503bfef3ebd6baca.diff
LOG: Revert "[FuncSpec][NFC] Refactor finding specialisation opportunities"
This reverts commit a8853924bd3c50deebfbf993c037257ccf9805f4 due to dependency
on a8b0f5801700
Added:
Modified:
llvm/lib/Transforms/IPO/FunctionSpecialization.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp
index ae7924c7ab966..4bf16883dc144 100644
--- a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp
@@ -315,9 +315,8 @@ class FunctionSpecializer {
<< F->getName() << " is " << Cost << "\n");
SmallVector<CallSpecBinding, 8> Specializations;
- if (!findSpecializations(F, Cost, Specializations)) {
- LLVM_DEBUG(
- dbgs() << "FnSpecialization: No possible specializations found\n");
+ if (!calculateGains(F, Cost, Specializations)) {
+ LLVM_DEBUG(dbgs() << "FnSpecialization: No possible constants found\n");
continue;
}
@@ -422,51 +421,35 @@ class FunctionSpecializer {
/// applying them.
///
/// \returns true if any specializations have been found.
- bool findSpecializations(Function *F, InstructionCost Cost,
- SmallVectorImpl<CallSpecBinding> &WorkList) {
- // Get a list of interesting arguments.
- SmallVector<Argument *, 4> Args;
- for (Argument &Arg : F->args())
- if (isArgumentInteresting(&Arg))
- Args.push_back(&Arg);
-
- if (!Args.size())
- return false;
-
- // Find all the call sites for the function.
+ bool calculateGains(Function *F, InstructionCost Cost,
+ SmallVectorImpl<CallSpecBinding> &WorkList) {
SpecializationMap Specializations;
- for (User *U : F->users()) {
- if (!isa<CallInst>(U) && !isa<InvokeInst>(U))
- continue;
- auto &CS = *cast<CallBase>(U);
- // If the call site has attribute minsize set, that callsite won't be
- // specialized.
- if (CS.hasFnAttr(Attribute::MinSize))
- continue;
-
- // If the parent of the call site will never be executed, we don't need
- // to worry about the passed value.
- if (!Solver.isBlockExecutable(CS.getParent()))
+ // Determine if we should specialize the function based on the values the
+ // argument can take on. If specialization is not profitable, we continue
+ // on to the next argument.
+ for (Argument &FormalArg : F->args()) {
+ // Determine if this argument is interesting. If we know the argument can
+ // take on any constant values, they are collected in Constants.
+ SmallVector<CallArgBinding, 8> ActualArgs;
+ if (!isArgumentInteresting(&FormalArg, ActualArgs)) {
+ LLVM_DEBUG(dbgs() << "FnSpecialization: Argument "
+ << FormalArg.getNameOrAsOperand()
+ << " is not interesting\n");
continue;
+ }
- // Examine arguments and create specialization candidates from call sites
- // with constant arguments.
- bool Added = false;
- for (Argument *A : Args) {
- Constant *C = getCandidateConstant(CS.getArgOperand(A->getArgNo()));
- if (!C)
- continue;
+ for (const auto &Entry : ActualArgs) {
+ CallBase *Call = Entry.first;
+ Constant *ActualArg = Entry.second;
- if (!Added) {
- Specializations[&CS] = {{}, 0 - Cost};
- Added = true;
- }
+ auto I = Specializations.insert({Call, SpecializationInfo()});
+ SpecializationInfo &S = I.first->second;
- SpecializationInfo &S = Specializations.back().second;
- S.Gain += getSpecializationBonus(A, C);
- S.Args.push_back({A, C});
+ if (I.second)
+ S.Gain = 0 - Cost;
+ S.Gain += getSpecializationBonus(&FormalArg, ActualArg);
+ S.Args.push_back({&FormalArg, ActualArg});
}
- Added = false;
}
// Remove unprofitable specializations.
@@ -670,21 +653,31 @@ class FunctionSpecializer {
return TotalCost + Bonus;
}
- /// Determine if it is possible to specialise the function for constant values
- /// of the formal parameter \p A.
- bool isArgumentInteresting(Argument *A) {
+ /// Determine if we should specialize a function based on the incoming values
+ /// of the given argument.
+ ///
+ /// This function implements the goal-directed heuristic. It determines if
+ /// specializing the function based on the incoming values of argument \p A
+ /// would result in any significant optimization opportunities. If
+ /// optimization opportunities exist, the constant values of \p A on which to
+ /// specialize the function are collected in \p Constants.
+ ///
+ /// \returns true if the function should be specialized on the given
+ /// argument.
+ bool isArgumentInteresting(Argument *A,
+ SmallVectorImpl<CallArgBinding> &Constants) {
+
// No point in specialization if the argument is unused.
if (A->user_empty())
return false;
// For now, don't attempt to specialize functions based on the values of
// composite types.
- Type *ArgTy = A->getType();
+ Type *ArgTy = A->getType() ;
if (!ArgTy->isSingleValueType())
return false;
- // Specialization of integer and floating point types needs to be explicitly
- // enabled.
+ // Specialization of integer and floating point types needs to be explicitly enabled.
if (!EnableSpecializationForLiteralConstant &&
(ArgTy->isIntegerTy() || ArgTy->isFloatingPointTy()))
return false;
@@ -705,46 +698,83 @@ class FunctionSpecializer {
return false;
}
+ // Collect the constant values that the argument can take on. If the
+ // argument can't take on any constant values, we aren't going to
+ // specialize the function. While it's possible to specialize the function
+ // based on non-constant arguments, there's likely not much benefit to
+ // constant propagation in doing so.
+ //
+ // TODO 1: currently it won't specialize if there are over the threshold of
+ // calls using the same argument, e.g foo(a) x 4 and foo(b) x 1, but it
+ // might be beneficial to take the occurrences into account in the cost
+ // model, so we would need to find the unique constants.
+ //
+ // TODO 2: this currently does not support constants, i.e. integer ranges.
+ //
+ getPossibleConstants(A, Constants);
+
+ if (Constants.empty())
+ return false;
+
+ LLVM_DEBUG(dbgs() << "FnSpecialization: Found interesting argument "
+ << A->getNameOrAsOperand() << "\n");
return true;
}
- /// Check if the valuy \p V (an actual argument) is a constant or can only
- /// have a constant value. Return that constant.
- Constant *getCandidateConstant(Value *V) {
- if (isa<PoisonValue>(V))
- return nullptr;
-
- // TrackValueOfGlobalVariable only tracks scalar global variables.
- if (auto *GV = dyn_cast<GlobalVariable>(V)) {
- // Check if we want to specialize on the address of non-constant
- // global values.
- if (!GV->isConstant() && !SpecializeOnAddresses)
- return nullptr;
+ /// Collect in \p Constants all the constant values that argument \p A can
+ /// take on.
+ void getPossibleConstants(Argument *A,
+ SmallVectorImpl<CallArgBinding> &Constants) {
+ Function *F = A->getParent();
- if (!GV->getValueType()->isSingleValueType())
- return nullptr;
- }
+ // Iterate over all the call sites of the argument's parent function.
+ for (User *U : F->users()) {
+ if (!isa<CallInst>(U) && !isa<InvokeInst>(U))
+ continue;
+ auto &CS = *cast<CallBase>(U);
+ // If the call site has attribute minsize set, that callsite won't be
+ // specialized.
+ if (CS.hasFnAttr(Attribute::MinSize))
+ continue;
- // Select for possible specialisation values that are constants or
- // are deduced to be constants or constant ranges with a single element.
- Constant *C = dyn_cast<Constant>(V);
- if (!C) {
- const ValueLatticeElement &LV = Solver.getLatticeValueFor(V);
- if (LV.isConstant())
- C = LV.getConstant();
- else if (LV.isConstantRange() &&
- LV.getConstantRange().isSingleElement()) {
- assert(V->getType()->isIntegerTy() && "Non-integral constant range");
- C = Constant::getIntegerValue(
- V->getType(), *LV.getConstantRange().getSingleElement());
- } else
- return nullptr;
- }
+ // If the parent of the call site will never be executed, we don't need
+ // to worry about the passed value.
+ if (!Solver.isBlockExecutable(CS.getParent()))
+ continue;
- LLVM_DEBUG(dbgs() << "FnSpecialization: Found interesting argument "
- << V->getNameOrAsOperand() << "\n");
+ auto *V = CS.getArgOperand(A->getArgNo());
+ if (isa<PoisonValue>(V))
+ continue;
- return C;
+ // TrackValueOfGlobalVariable only tracks scalar global variables.
+ if (auto *GV = dyn_cast<GlobalVariable>(V)) {
+ // Check if we want to specialize on the address of non-constant
+ // global values.
+ if (!GV->isConstant() && !SpecializeOnAddresses)
+ continue;
+
+ if (!GV->getValueType()->isSingleValueType())
+ continue;
+ }
+
+ // Select for possible specialisation arguments which are constants or
+ // are deduced to be constants or constant ranges with a single element.
+ Constant *C = dyn_cast<Constant>(V);
+ if (!C) {
+ const ValueLatticeElement &LV = Solver.getLatticeValueFor(V);
+ if (LV.isConstant())
+ C = LV.getConstant();
+ else if (LV.isConstantRange() &&
+ LV.getConstantRange().isSingleElement()) {
+ assert(V->getType()->isIntegerTy() && "Non-integral constant range");
+ C = Constant::getIntegerValue(
+ V->getType(), *LV.getConstantRange().getSingleElement());
+ } else
+ continue;
+ }
+
+ Constants.push_back({&CS, C});
+ }
}
/// Rewrite calls to function \p F to call function \p Clone instead.
More information about the llvm-commits
mailing list