[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