[llvm] a8b0f58 - [FuncSpec] Fix specialisation based on literals

Momchil Velikov via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 26 02:05:12 PDT 2022


Author: Momchil Velikov
Date: 2022-10-26T09:55:33+01:00
New Revision: a8b0f580170089fcd555ade5565ceff0ec60f609

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

LOG: [FuncSpec] Fix specialisation based on literals

The `FunctionSpecialization` pass has support for specialising
functions, which are called with literal arguments. This functionality
is disabled by default and is enabled with the option
`-function-specialization-for-literal-constant` .  There are a few
issues with the implementation, though:

* even with the default, the pass will still specialise based on
   floating-point literals

* even when it's enabled, the pass will specialise only for the `i1`
    type (or `i2` if all of the possible 4 values occur, or `i3` if all
    of the possible 8 values occur, etc)

The reason for this is incorrect check of the lattice value of the
function formal parameter. The lattice value is `overdefined` when the
constant range of the possible arguments is the full set, and this is
the reason for the specialisation to trigger. However, if the set of
the possible arguments is not the full set, that must not prevent the
specialisation.

This patch changes the pass to NOT consider a formal parameter when
specialising a function if the lattice value for that parameter is:

* unknown or undef
* a constant
* a constant range with a single element

on the basis that specialisation is pointless for those cases.

Is also changes the criteria for picking up an actual argument to
specialise if the argument is:

* a LLVM IR constant
* has `constant` lattice value
 has `constantrange` lattice value with a single element.

Reviewed By: ChuanqiXu

Differential Revision: https://reviews.llvm.org/D135893

Added: 
    llvm/test/Transforms/FunctionSpecialization/literal-const.ll

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 94b36f9165cd6..82110c7ee5e4a 100644
--- a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp
@@ -666,17 +666,35 @@ class FunctionSpecializer {
   /// 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.
-    if (!A->getType()->isSingleValueType() || A->user_empty())
+    Type *ArgTy = A->getType()                              ;
+    if (!ArgTy->isSingleValueType())
+      return false;
+
+    // Specialization of integer and floating point types needs to be explicitly enabled.
+    if (!EnableSpecializationForLiteralConstant &&
+        (ArgTy->isIntegerTy() || ArgTy->isFloatingPointTy()))
       return false;
 
-    // If the argument isn't overdefined, there's nothing to do. It should
-    // already be constant.
-    if (!Solver.getLatticeValueFor(A).isOverdefined()) {
+    // SCCP solver does not record an argument that will be constructed on
+    // stack.
+    if (A->hasByValAttr() && !A->getParent()->onlyReadsMemory())
+      return false;
+
+    // Check the lattice value and decide if we should attemt to specialize,
+    // based on this argument. No point in specialization, if the lattice value
+    // is already a constant.
+    const ValueLatticeElement &LV = Solver.getLatticeValueFor(A);
+    if (LV.isUnknownOrUndef() || LV.isConstant() ||
+        (LV.isConstantRange() && LV.getConstantRange().isSingleElement())) {
       LLVM_DEBUG(dbgs() << "FnSpecialization: Nothing to do, argument "
-                        << A->getNameOrAsOperand()
-                        << " is already constant?\n");
+                        << A->getNameOrAsOperand() << " is already constant\n");
       return false;
     }
 
@@ -709,11 +727,6 @@ class FunctionSpecializer {
                             SmallVectorImpl<CallArgBinding> &Constants) {
     Function *F = A->getParent();
 
-    // SCCP solver does not record an argument that will be constructed on
-    // stack.
-    if (A->hasByValAttr() && !F->onlyReadsMemory())
-      return;
-
     // Iterate over all the call sites of the argument's parent function.
     for (User *U : F->users()) {
       if (!isa<CallInst>(U) && !isa<InvokeInst>(U))
@@ -744,9 +757,23 @@ class FunctionSpecializer {
           continue;
       }
 
-      if (isa<Constant>(V) && (Solver.getLatticeValueFor(V).isConstant() ||
-                               EnableSpecializationForLiteralConstant))
-        Constants.push_back({&CS, cast<Constant>(V)});
+      // 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});
     }
   }
 

diff  --git a/llvm/test/Transforms/FunctionSpecialization/literal-const.ll b/llvm/test/Transforms/FunctionSpecialization/literal-const.ll
new file mode 100644
index 0000000000000..9bd9440551cdd
--- /dev/null
+++ b/llvm/test/Transforms/FunctionSpecialization/literal-const.ll
@@ -0,0 +1,73 @@
+; RUN: opt -S --passes=function-specialization \
+; RUN:        -force-function-specialization < %s | FileCheck %s -check-prefix CHECK-NOLIT
+; RUN: opt -S --passes=function-specialization \
+; RUN:        -function-specialization-for-literal-constant \
+; RUN:        -force-function-specialization < %s | FileCheck %s -check-prefix CHECK-LIT
+
+define dso_local i32 @f0(i32 noundef %x) {
+entry:
+  %call = tail call fastcc i32 @neg(i32 noundef %x, i1 noundef zeroext false)
+  ret i32 %call
+}
+
+define internal fastcc i32 @neg(i32 noundef %x, i1 noundef zeroext %b) {
+entry:
+  %sub = sub nsw i32 0, %x
+  %cond = select i1 %b, i32 %sub, i32 %x
+  ret i32 %cond
+}
+
+define dso_local i32 @f1(i32 noundef %x) {
+entry:
+  %call = tail call fastcc i32 @neg(i32 noundef %x, i1 noundef zeroext true)
+  ret i32 %call
+}
+
+define dso_local i32 @g0(i32 noundef %x) {
+entry:
+  %call = tail call fastcc i32 @add(i32 noundef %x, i32 noundef 1)
+  ret i32 %call
+}
+
+define internal fastcc i32 @add(i32 noundef %x, i32 noundef %y) {
+entry:
+  %add = add nsw i32 %y, %x
+  ret i32 %add
+}
+
+define dso_local i32 @g1(i32 noundef %x) {
+entry:
+  %call = tail call fastcc i32 @add(i32 noundef %x, i32 noundef 2)
+  ret i32 %call
+}
+
+define dso_local float @h0(float noundef %x) {
+entry:
+  %call = tail call fastcc float @addf(float noundef %x, float noundef 1.000000e+00)
+  ret float %call
+}
+
+define internal fastcc float @addf(float noundef %x, float noundef %y) {
+entry:
+  %add = fadd float %x, %y
+  ret float %add
+}
+
+define dso_local float @h1(float noundef %x) {
+entry:
+  %call = tail call fastcc float @addf(float noundef %x, float noundef 2.000000e+00)
+  ret float %call
+}
+
+; Check no functions were specialised.
+; CHECK-NOLIT-NOT: @neg.
+; CHECK-NOLIT-NOT: @add.
+; CHECK-NOLIT-NOT: @addf.
+
+; Check all of `neg`, `add`, and `addf` were specialised.
+; CHECK-LIT-DAG: @neg.1
+; CHECK-LIT-DAG: @neg.2
+; CHECK-LIT-DAG: @add.3
+; CHECK-LIT-DAG: @add.4
+; CHECK-LIT-DAG: @addf.5
+; CHECK-LIT-DAG: @addf.6


        


More information about the llvm-commits mailing list