[llvm] 5b139a5 - Revert "[FuncSpec] Decouple cost/benefit analysis, allowing sorting of candidates."

Sjoerd Meijer via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 16 04:58:35 PST 2021


Author: Sjoerd Meijer
Date: 2021-12-16T12:56:11Z
New Revision: 5b139a583ddc5805748e0c601d69c78bafc97570

URL: https://github.com/llvm/llvm-project/commit/5b139a583ddc5805748e0c601d69c78bafc97570
DIFF: https://github.com/llvm/llvm-project/commit/5b139a583ddc5805748e0c601d69c78bafc97570.diff

LOG: Revert "[FuncSpec] Decouple cost/benefit analysis, allowing sorting of candidates."

This reverts commit 20b03d65364d963585bf16f175b367f3842f223a.

This shows some failed tests on a bot with expensive checks enabled that I need
to look at.

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 ec56e7b011060..fbd083bb9bbfd 100644
--- a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp
@@ -92,25 +92,6 @@ static cl::opt<bool> EnableSpecializationForLiteralConstant(
     cl::desc("Enable specialization of functions that take a literal constant "
              "as an argument."));
 
-namespace {
-// Bookkeeping struct to pass data from the analysis and profitability phase
-// to the actual transform helper functions.
-struct ArgInfo {
-  Function *Fn;         // The function to perform specialisation on.
-  Argument *Arg;        // The Formal argument being analysed.
-  Constant *Const;      // A corresponding actual constant argument.
-  InstructionCost Gain; // Profitability: Gain = Bonus - Cost.
-
-  // Flag if this will be a partial specialization, in which case we will need
-  // to keep the original function around in addition to the added
-  // specializations.
-  bool Partial = false;
-
-  ArgInfo(Function *F, Argument *A, Constant *C, InstructionCost G)
-      : Fn(F), Arg(A), Const(C), Gain(G){};
-};
-} // Anonymous namespace
-
 // Helper to check if \p LV is either a constant or a constant
 // range with a single element. This should cover exactly the same cases as the
 // old ValueLatticeElement::isConstant() and is intended to be used in the
@@ -275,27 +256,16 @@ class FunctionSpecializer {
   bool
   specializeFunctions(SmallVectorImpl<Function *> &FuncDecls,
                       SmallVectorImpl<Function *> &CurrentSpecializations) {
+
+    // Attempt to specialize the argument-tracked functions.
     bool Changed = false;
     for (auto *F : FuncDecls) {
-      if (!isCandidateFunction(F, CurrentSpecializations))
-        continue;
-
-      auto Cost = getSpecializationCost(F);
-      if (!Cost.isValid()) {
-        LLVM_DEBUG(
-            dbgs() << "FnSpecialization: Invalid specialisation cost.\n");
-        continue;
-      }
-
-      auto ConstArgs = calculateGains(F, Cost);
-      if (ConstArgs.empty()) {
-        LLVM_DEBUG(dbgs() << "FnSpecialization: no possible constants found\n");
-        continue;
-      }
-
-      for (auto &CA : ConstArgs) {
-        specializeFunction(CA, CurrentSpecializations);
+      if (specializeFunction(F, CurrentSpecializations)) {
         Changed = true;
+        LLVM_DEBUG(dbgs() << "FnSpecialization: Can specialize this func.\n");
+      } else {
+        LLVM_DEBUG(
+            dbgs() << "FnSpecialization: Cannot specialize this func.\n");
       }
     }
 
@@ -363,79 +333,15 @@ class FunctionSpecializer {
     return Clone;
   }
 
-  /// This function decides whether it's worthwhile to specialize function \p F
-  /// based on the known constant values its arguments can take on, i.e. it
-  /// calculates a gain and returns a list of actual arguments that are deemed
-  /// profitable to specialize. Specialization is performed on the first
-  /// interesting argument. Specializations based on additional arguments will
-  /// be evaluated on following iterations of the main IPSCCP solve loop.
-  SmallVector<ArgInfo> calculateGains(Function *F, InstructionCost Cost) {
-    SmallVector<ArgInfo> Worklist;
-    // 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()) {
-      LLVM_DEBUG(dbgs() << "FnSpecialization: Analysing arg: "
-                        << FormalArg.getName() << "\n");
-      // Determine if this argument is interesting. If we know the argument can
-      // take on any constant values, they are collected in Constants. If the
-      // argument can only ever equal a constant value in Constants, the
-      // function will be completely specialized, and the IsPartial flag will
-      // be set to false by isArgumentInteresting (that function only adds
-      // values to the Constants list that are deemed profitable).
-      bool IsPartial = true;
-      SmallVector<Constant *> ActualConstArg;
-      if (!isArgumentInteresting(&FormalArg, ActualConstArg, IsPartial)) {
-        LLVM_DEBUG(dbgs() << "FnSpecialization: Argument is not interesting\n");
-        continue;
-      }
-
-      for (auto *ActualArg : ActualConstArg) {
-        InstructionCost Gain =
-            ForceFunctionSpecialization
-                ? 1
-                : getSpecializationBonus(&FormalArg, ActualArg) - Cost;
-
-        if (Gain <= 0)
-          continue;
-        Worklist.push_back({F, &FormalArg, ActualArg, Gain});
-      }
-
-      if (Worklist.empty())
-        continue;
-
-      // Sort the candidates in descending order.
-      llvm::sort(Worklist,
-                 [](ArgInfo &L, ArgInfo &R) { return L.Gain > R.Gain; });
-
-      // TODO: truncate the worklist to 'MaxConstantsThreshold' candidates if
-      // necessary.
-      if (Worklist.size() > MaxConstantsThreshold) {
-        Worklist.clear();
-        continue;
-      }
-
-      if (IsPartial || Worklist.size() < ActualConstArg.size())
-        for (auto &ActualArg : Worklist)
-          ActualArg.Partial = true;
-
-      LLVM_DEBUG(dbgs() << "Sorted list of candidates by gain:\n";
-                 for (auto &C
-                      : Worklist) {
-                   dbgs() << "- Function = " << C.Fn->getName() << ", ";
-                   dbgs() << "FormalArg = " << C.Arg->getName() << ", ";
-                   dbgs() << "ActualArg = " << C.Const->getName() << ", ";
-                   dbgs() << "Gain = " << C.Gain << "\n";
-                 });
-
-      // FIXME: Only one argument per function.
-      break;
-    }
-    return Worklist;
-  }
+  /// This function decides whether to specialize function \p F based on the
+  /// known constant values its arguments can take on. Specialization is
+  /// performed on the first interesting argument. Specializations based on
+  /// additional arguments will be evaluated on following iterations of the
+  /// main IPSCCP solve loop. \returns true if the function is specialized and
+  /// false otherwise.
+  bool specializeFunction(Function *F,
+                          SmallVectorImpl<Function *> &Specializations) {
 
-  bool isCandidateFunction(Function *F,
-                           SmallVectorImpl<Function *> &Specializations) {
     // Do not specialize the cloned function again.
     if (SpecializedFuncs.contains(F))
       return false;
@@ -456,33 +362,84 @@ class FunctionSpecializer {
 
     LLVM_DEBUG(dbgs() << "FnSpecialization: Try function: " << F->getName()
                       << "\n");
-    return true;
-  }
 
-  void specializeFunction(ArgInfo &AI,
-                          SmallVectorImpl<Function *> &Specializations) {
-    Function *Clone = cloneCandidateFunction(AI.Fn);
-    Argument *ClonedArg = Clone->getArg(AI.Arg->getArgNo());
+    // Determine if it would be profitable to create a specialization of the
+    // function where the argument takes on the given constant value. If so,
+    // add the constant to Constants.
+    auto FnSpecCost = getSpecializationCost(F);
+    if (!FnSpecCost.isValid()) {
+      LLVM_DEBUG(dbgs() << "FnSpecialization: Invalid specialisation cost.\n");
+      return false;
+    }
 
-    // Rewrite calls to the function so that they call the clone instead.
-    rewriteCallSites(AI.Fn, Clone, *ClonedArg, AI.Const);
+    LLVM_DEBUG(dbgs() << "FnSpecialization: func specialisation cost: ";
+               FnSpecCost.print(dbgs()); dbgs() << "\n");
 
-    // Initialize the lattice state of the arguments of the function clone,
-    // marking the argument on which we specialized the function constant
-    // with the given value.
-    Solver.markArgInFuncSpecialization(AI.Fn, ClonedArg, AI.Const);
+    // 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 &A : F->args()) {
+      LLVM_DEBUG(dbgs() << "FnSpecialization: Analysing arg: " << A.getName()
+                        << "\n");
+      // True if this will be a partial specialization. We will need to keep
+      // the original function around in addition to the added specializations.
+      bool IsPartial = true;
 
-    // Mark all the specialized functions
-    Specializations.push_back(Clone);
-    NbFunctionsSpecialized++;
+      // Determine if this argument is interesting. If we know the argument can
+      // take on any constant values, they are collected in Constants. If the
+      // argument can only ever equal a constant value in Constants, the
+      // function will be completely specialized, and the IsPartial flag will
+      // be set to false by isArgumentInteresting (that function only adds
+      // values to the Constants list that are deemed profitable).
+      SmallVector<Constant *, 4> Constants;
+      if (!isArgumentInteresting(&A, Constants, FnSpecCost, IsPartial)) {
+        LLVM_DEBUG(dbgs() << "FnSpecialization: Argument is not interesting\n");
+        continue;
+      }
 
-    // If the function has been completely specialized, the original function
-    // is no longer needed. Mark it unreachable.
-    if (!AI.Partial)
-      Solver.markFunctionUnreachable(AI.Fn);
+      assert(!Constants.empty() && "No constants on which to specialize");
+      LLVM_DEBUG(dbgs() << "FnSpecialization: Argument is interesting!\n"
+                        << "FnSpecialization: Specializing '" << F->getName()
+                        << "' on argument: " << A << "\n"
+                        << "FnSpecialization: Constants are:\n\n";
+                 for (unsigned I = 0; I < Constants.size(); ++I) dbgs()
+                 << *Constants[I] << "\n";
+                 dbgs() << "FnSpecialization: End of constants\n\n");
+
+      // Create a version of the function in which the argument is marked
+      // constant with the given value.
+      for (auto *C : Constants) {
+        // Clone the function. We leave the ValueToValueMap empty to allow
+        // IPSCCP to propagate the constant arguments.
+        Function *Clone = cloneCandidateFunction(F);
+        Argument *ClonedArg = Clone->arg_begin() + A.getArgNo();
+
+        // Rewrite calls to the function so that they call the clone instead.
+        rewriteCallSites(F, Clone, *ClonedArg, C);
+
+        // Initialize the lattice state of the arguments of the function clone,
+        // marking the argument on which we specialized the function constant
+        // with the given value.
+        Solver.markArgInFuncSpecialization(F, ClonedArg, C);
+
+        // Mark all the specialized functions
+        Specializations.push_back(Clone);
+        NbFunctionsSpecialized++;
+      }
+
+      // If the function has been completely specialized, the original function
+      // is no longer needed. Mark it unreachable.
+      if (!IsPartial)
+        Solver.markFunctionUnreachable(F);
+
+      // FIXME: Only one argument per function.
+      return true;
+    }
+
+    return false;
   }
 
-  /// Compute and return the cost of specializing function \p F.
+  /// Compute the cost of specializing function \p F.
   InstructionCost getSpecializationCost(Function *F) {
     // Compute the code metrics for the function.
     SmallPtrSet<const Value *, 32> EphValues;
@@ -623,6 +580,7 @@ class FunctionSpecializer {
   /// argument.
   bool isArgumentInteresting(Argument *A,
                              SmallVectorImpl<Constant *> &Constants,
+                             const InstructionCost &FnSpecCost,
                              bool &IsPartial) {
     // For now, don't attempt to specialize functions based on the values of
     // composite types.
@@ -650,8 +608,42 @@ class FunctionSpecializer {
     //
     // TODO 2: this currently does not support constants, i.e. integer ranges.
     //
-    IsPartial = !getPossibleConstants(A, Constants);
-    LLVM_DEBUG(dbgs() << "FnSpecialization: interesting arg: " << *A << "\n");
+    SmallVector<Constant *, 4> PossibleConstants;
+    bool AllConstant = getPossibleConstants(A, PossibleConstants);
+    if (PossibleConstants.empty()) {
+      LLVM_DEBUG(dbgs() << "FnSpecialization: no possible constants found\n");
+      return false;
+    }
+    if (PossibleConstants.size() > MaxConstantsThreshold) {
+      LLVM_DEBUG(dbgs() << "FnSpecialization: number of constants found exceed "
+                        << "the maximum number of constants threshold.\n");
+      return false;
+    }
+
+    for (auto *C : PossibleConstants) {
+      LLVM_DEBUG(dbgs() << "FnSpecialization: Constant: " << *C << "\n");
+      if (ForceFunctionSpecialization) {
+        LLVM_DEBUG(dbgs() << "FnSpecialization: Forced!\n");
+        Constants.push_back(C);
+        continue;
+      }
+      if (getSpecializationBonus(A, C) > FnSpecCost) {
+        LLVM_DEBUG(dbgs() << "FnSpecialization: profitable!\n");
+        Constants.push_back(C);
+      } else {
+        LLVM_DEBUG(dbgs() << "FnSpecialization: not profitable\n");
+      }
+    }
+
+    // None of the constant values the argument can take on were deemed good
+    // candidates on which to specialize the function.
+    if (Constants.empty())
+      return false;
+
+    // This will be a partial specialization if some of the constants were
+    // rejected due to their profitability.
+    IsPartial = !AllConstant || PossibleConstants.size() != Constants.size();
+
     return true;
   }
 
@@ -689,7 +681,7 @@ class FunctionSpecializer {
 
       // For now, constant expressions are fine but only if they are function
       // calls.
-      if (auto *CE = dyn_cast<ConstantExpr>(V))
+      if (auto *CE =  dyn_cast<ConstantExpr>(V))
         if (!isa<Function>(CE->getOperand(0)))
           return false;
 


        


More information about the llvm-commits mailing list