[llvm] [TLI] Pass replace-with-veclib works with Scalable Vectors. (PR #73642)

Maciej Gabka via llvm-commits llvm-commits at lists.llvm.org
Wed Dec 13 09:06:46 PST 2023


================
@@ -38,138 +42,166 @@ STATISTIC(NumTLIFuncDeclAdded,
 STATISTIC(NumFuncUsedAdded,
           "Number of functions added to `llvm.compiler.used`");
 
-static bool replaceWithTLIFunction(CallInst &CI, const StringRef TLIName) {
-  Module *M = CI.getModule();
-
-  Function *OldFunc = CI.getCalledFunction();
-
-  // Check if the vector library function is already declared in this module,
-  // otherwise insert it.
+/// Returns a vector Function that it adds to the Module \p M. When an \p
+/// OptOldFunc is given, it copies its attributes to the newly created Function.
+Function *getTLIFunction(Module *M, FunctionType *VectorFTy,
+                         std::optional<Function *> OptOldFunc,
+                         const StringRef TLIName) {
   Function *TLIFunc = M->getFunction(TLIName);
   if (!TLIFunc) {
-    TLIFunc = Function::Create(OldFunc->getFunctionType(),
-                               Function::ExternalLinkage, TLIName, *M);
-    TLIFunc->copyAttributesFrom(OldFunc);
+    TLIFunc =
+        Function::Create(VectorFTy, Function::ExternalLinkage, TLIName, *M);
+    if (OptOldFunc)
+      TLIFunc->copyAttributesFrom(*OptOldFunc);
 
     LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": Added vector library function `"
                       << TLIName << "` of type `" << *(TLIFunc->getType())
                       << "` to module.\n");
 
     ++NumTLIFuncDeclAdded;
-
-    // Add the freshly created function to llvm.compiler.used,
-    // similar to as it is done in InjectTLIMappings
+    // Add the freshly created function to llvm.compiler.used, similar to as it
+    // is done in InjectTLIMappings
     appendToCompilerUsed(*M, {TLIFunc});
-
     LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": Adding `" << TLIName
                       << "` to `@llvm.compiler.used`.\n");
     ++NumFuncUsedAdded;
   }
+  return TLIFunc;
+}
 
-  // Replace the call to the vector intrinsic with a call
-  // to the corresponding function from the vector library.
+/// Replace the call to the vector intrinsic ( \p OldFunc ) with a call to the
+/// corresponding function from the vector library ( \p TLIFunc ).
+static bool replaceWithTLIFunction(const Module *M, CallInst &CI,
+                                   const ElementCount &VecVF, Function *OldFunc,
+                                   Function *TLIFunc, FunctionType *VecFTy,
+                                   bool IsMasked) {
   IRBuilder<> IRBuilder(&CI);
   SmallVector<Value *> Args(CI.args());
+  if (IsMasked) {
+    if (Args.size() == VecFTy->getNumParams())
+      static_assert(true && "mask was already in place");
+
+    auto *MaskTy = VectorType::get(Type::getInt1Ty(M->getContext()), VecVF);
+    Args.push_back(Constant::getAllOnesValue(MaskTy));
+  }
+
   // Preserve the operand bundles.
   SmallVector<OperandBundleDef, 1> OpBundles;
   CI.getOperandBundlesAsDefs(OpBundles);
   CallInst *Replacement = IRBuilder.CreateCall(TLIFunc, Args, OpBundles);
-  assert(OldFunc->getFunctionType() == TLIFunc->getFunctionType() &&
+  assert(VecFTy == TLIFunc->getFunctionType() &&
          "Expecting function types to be identical");
   CI.replaceAllUsesWith(Replacement);
-  if (isa<FPMathOperator>(Replacement)) {
-    // Preserve fast math flags for FP math.
+  // Preserve fast math flags for FP math.
+  if (isa<FPMathOperator>(Replacement))
     Replacement->copyFastMathFlags(&CI);
-  }
 
   LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": Replaced call to `"
-                    << OldFunc->getName() << "` with call to `" << TLIName
-                    << "`.\n");
+                    << OldFunc->getName() << "` with call to `"
+                    << TLIFunc->getName() << "`.\n");
   ++NumCallsReplaced;
   return true;
 }
 
+/// Utility method to get the VecDesc, depending on whether there is a TLI
+/// mapping, either with or without a mask.
+static std::optional<const VecDesc *> getVecDesc(const TargetLibraryInfo &TLI,
+                                                 const StringRef &ScalarName,
+                                                 const ElementCount &VF) {
+  const VecDesc *VDMasked = TLI.getVectorMappingInfo(ScalarName, VF, true);
+  const VecDesc *VDNoMask = TLI.getVectorMappingInfo(ScalarName, VF, false);
+  // Invalid when there are both variants (ie masked and unmasked), or none
+  if ((VDMasked == nullptr) == (VDNoMask == nullptr))
+    return std::nullopt;
+
+  return {VDMasked != nullptr ? VDMasked : VDNoMask};
+}
+
----------------
mgabka wrote:

this isn't correct, for given scalar function we may have both masked and non masked mappings.
Libraries like SLEEF provide both:

nm libsleefgnuabi.so.3.6 | grep -E "_ZGVs(N|M)xv_acosh"
0000000000026e84 T _ZGVsMxv_acosh
00000000000306c0 T _ZGVsMxv_acoshf
0000000000022bd0 T _ZGVsNxv_acosh
000000000002d180 T _ZGVsNxv_acoshf

it is just mappings aren't added to TLI at the moment.


Since we do not expect to see here predicated vector intrinsics, I think we can always firstly get the non masked version and if such does not exist then take the masked one.


https://github.com/llvm/llvm-project/pull/73642


More information about the llvm-commits mailing list