[llvm] [Analysis][NFC] Make VecDesc constexpr and relocation-free (PR #201145)

Alexis Engelke via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 2 08:46:06 PDT 2026


https://github.com/aengelke updated https://github.com/llvm/llvm-project/pull/201145

>From 75334ff1c37049ebc48f7beabc9fb71a7f75f5a4 Mon Sep 17 00:00:00 2001
From: Alexis Engelke <engelke at in.tum.de>
Date: Tue, 2 Jun 2026 15:28:01 +0000
Subject: [PATCH 1/2] [spr] initial version

Created using spr 1.3.8-wip
---
 .../include/llvm/Analysis/TargetLibraryInfo.h |  53 +++--
 llvm/lib/Analysis/TargetLibraryInfo.cpp       | 183 +++++++++++++-----
 llvm/unittests/Analysis/CMakeLists.txt        |   1 -
 .../Analysis/ReplaceWithVecLibTest.cpp        | 115 -----------
 4 files changed, 169 insertions(+), 183 deletions(-)
 delete mode 100644 llvm/unittests/Analysis/ReplaceWithVecLibTest.cpp

diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.h b/llvm/include/llvm/Analysis/TargetLibraryInfo.h
index 629b126db17c2..6450a8a05f8c0 100644
--- a/llvm/include/llvm/Analysis/TargetLibraryInfo.h
+++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.h
@@ -43,27 +43,42 @@ template <typename T> class ArrayRef;
 /// <scalarname> = the name of the scalar function.
 /// <vectorname> = the name of the vector function.
 class VecDesc {
-  StringRef ScalarFnName;
-  StringRef VectorFnName;
-  ElementCount VectorizationFactor;
-  bool Masked;
-  StringRef VABIPrefix;
-  std::optional<CallingConv::ID> CC;
+  friend struct VecDescBuilder;
+
+  // String offsets are relative to the this pointer.
+  uint16_t ScalarFnNameOff = 0;
+  uint16_t ScalarFnNameSize = 0;
+  uint16_t VectorFnNameOff = 0;
+  uint16_t VectorFnNameSize = 0;
+  ElementCount VectorizationFactor = {};
+  bool Masked = false;
+  uint16_t VABIPrefixOff = 0;
+  uint16_t VABIPrefixSize = 0;
+  std::optional<CallingConv::ID> CC = {};
+
+  constexpr VecDesc() {}
+
+  // Due to the relative string offsets, VecDesc is neither copyable nor
+  // movable. The move constructor has to exist to allow assignment to a
+  // variable.
+  VecDesc(const VecDesc &) = delete;
+  VecDesc(VecDesc &&) = default;
 
 public:
-  VecDesc() = delete;
-  VecDesc(StringRef ScalarFnName, StringRef VectorFnName,
-          ElementCount VectorizationFactor, bool Masked, StringRef VABIPrefix,
-          std::optional<CallingConv::ID> Conv)
-      : ScalarFnName(ScalarFnName), VectorFnName(VectorFnName),
-        VectorizationFactor(VectorizationFactor), Masked(Masked),
-        VABIPrefix(VABIPrefix), CC(Conv) {}
-
-  StringRef getScalarFnName() const { return ScalarFnName; }
-  StringRef getVectorFnName() const { return VectorFnName; }
+  StringRef getScalarFnName() const {
+    return StringRef(reinterpret_cast<const char *>(this) + ScalarFnNameOff,
+                     ScalarFnNameSize);
+  }
+  StringRef getVectorFnName() const {
+    return StringRef(reinterpret_cast<const char *>(this) + VectorFnNameOff,
+                     VectorFnNameSize);
+  }
   ElementCount getVectorizationFactor() const { return VectorizationFactor; }
   bool isMasked() const { return Masked; }
-  StringRef getVABIPrefix() const { return VABIPrefix; }
+  StringRef getVABIPrefix() const {
+    return StringRef(reinterpret_cast<const char *>(this) + VABIPrefixOff,
+                     VABIPrefixSize);
+  }
   std::optional<CallingConv::ID> getCallingConv() const { return CC; }
 
   /// Returns a vector function ABI variant string on the form:
@@ -104,10 +119,10 @@ class TargetLibraryInfoImpl {
   }
 
   /// Vectorization descriptors - sorted by ScalarFnName.
-  std::vector<VecDesc> VectorDescs;
+  std::vector<const VecDesc *> VectorDescs;
   /// Scalarization descriptors - same content as VectorDescs but sorted based
   /// on VectorFnName rather than ScalarFnName.
-  std::vector<VecDesc> ScalarDescs;
+  std::vector<const VecDesc *> ScalarDescs;
 
   /// Return true if the function type FTy is valid for the library function
   /// F, regardless of whether the function is available.
diff --git a/llvm/lib/Analysis/TargetLibraryInfo.cpp b/llvm/lib/Analysis/TargetLibraryInfo.cpp
index 6b8f861392254..701c84dc99ce3 100644
--- a/llvm/lib/Analysis/TargetLibraryInfo.cpp
+++ b/llvm/lib/Analysis/TargetLibraryInfo.cpp
@@ -25,10 +25,12 @@ using namespace llvm;
 #include "llvm/Analysis/TargetLibraryInfo.inc"
 
 std::string VecDesc::getVectorFunctionABIVariantString() const {
-  assert(!VectorFnName.empty() && "Vector function name must not be empty.");
+  assert(!getVectorFnName().empty() &&
+         "Vector function name must not be empty.");
   SmallString<256> Buffer;
   llvm::raw_svector_ostream Out(Buffer);
-  Out << VABIPrefix << "_" << ScalarFnName << "(" << VectorFnName << ")";
+  Out << getVABIPrefix() << "_" << getScalarFnName() << "(" << getVectorFnName()
+      << ")";
   return std::string(Out.str());
 }
 
@@ -1223,109 +1225,197 @@ void TargetLibraryInfoImpl::disableAllFunctions() {
   memset(AvailableArray, 0, sizeof(AvailableArray));
 }
 
-static bool compareByScalarFnName(const VecDesc &LHS, const VecDesc &RHS) {
-  return LHS.getScalarFnName() < RHS.getScalarFnName();
+static bool compareByScalarFnName(const VecDesc *LHS, const VecDesc *RHS) {
+  return LHS->getScalarFnName() < RHS->getScalarFnName();
 }
 
-static bool compareByVectorFnName(const VecDesc &LHS, const VecDesc &RHS) {
-  return LHS.getVectorFnName() < RHS.getVectorFnName();
+static bool compareByVectorFnName(const VecDesc *LHS, const VecDesc *RHS) {
+  return LHS->getVectorFnName() < RHS->getVectorFnName();
 }
 
-static bool compareWithScalarFnName(const VecDesc &LHS, StringRef S) {
-  return LHS.getScalarFnName() < S;
+static bool compareWithScalarFnName(const VecDesc *LHS, StringRef S) {
+  return LHS->getScalarFnName() < S;
 }
 
 void TargetLibraryInfoImpl::addVectorizableFunctions(ArrayRef<VecDesc> Fns) {
-  llvm::append_range(VectorDescs, Fns);
+  for (const VecDesc &Desc : Fns)
+    VectorDescs.push_back(&Desc);
   llvm::sort(VectorDescs, compareByScalarFnName);
 
-  llvm::append_range(ScalarDescs, Fns);
+  for (const VecDesc &Desc : Fns)
+    ScalarDescs.push_back(&Desc);
   llvm::sort(ScalarDescs, compareByVectorFnName);
 }
 
-static const VecDesc VecFuncs_Accelerate[] = {
+struct VecDescData {
+  StringRef ScalarFnName;
+  StringRef VectorFnName;
+  ElementCount VectorizationFactor;
+  bool Masked;
+  StringRef VABIPrefix;
+  std::optional<CallingConv::ID> CC;
+};
+
+namespace llvm {
+struct VecDescBuilder {
+  template <size_t M, size_t N>
+  static constexpr auto build(const char (&StrTab)[M],
+                              const VecDescData (&Data)[N]) {
+    struct {
+      VecDesc Descs[N];
+      char StringTable[M];
+
+      operator ArrayRef<VecDesc>() const { return ArrayRef(Descs, N); }
+    } Ret{};
+    for (size_t i = 0; i != M; i++)
+      Ret.StringTable[i] = StrTab[i];
+    size_t Off = offsetof(decltype(Ret), StringTable);
+    for (size_t i = 0; i != N; i++) {
+      assert(Off < UINT16_MAX);
+      Ret.Descs[i].ScalarFnNameOff = Off;
+      Off += Data[i].ScalarFnName.size();
+      Ret.Descs[i].ScalarFnNameSize = Data[i].ScalarFnName.size();
+      Ret.Descs[i].VectorFnNameOff = Off;
+      Off += Data[i].VectorFnName.size();
+      Ret.Descs[i].VectorFnNameSize = Data[i].VectorFnName.size();
+      Ret.Descs[i].VectorizationFactor = Data[i].VectorizationFactor;
+      Ret.Descs[i].Masked = Data[i].Masked;
+      Ret.Descs[i].VABIPrefixOff = Off;
+      Off += Data[i].VABIPrefix.size();
+      Ret.Descs[i].VABIPrefixSize = Data[i].VABIPrefix.size();
+      Ret.Descs[i].CC = Data[i].CC;
+      Off -= sizeof(VecDesc);
+    }
+    return Ret;
+  }
+};
+} // namespace llvm
+
 #define TLI_DEFINE_ACCELERATE_VECFUNCS
+static constexpr auto VecFuncs_Accelerate = VecDescBuilder::build(
+#define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, VABI_PREFIX) SCAL VEC VABI_PREFIX
+#include "llvm/Analysis/VecFuncs.def"
+    , {
 #include "llvm/Analysis/VecFuncs.def"
+      });
 #undef TLI_DEFINE_ACCELERATE_VECFUNCS
-};
 
-static const VecDesc VecFuncs_DarwinLibSystemM[] = {
 #define TLI_DEFINE_DARWIN_LIBSYSTEM_M_VECFUNCS
+static constexpr auto VecFuncs_DarwinLibSystemM = VecDescBuilder::build(
+#define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, VABI_PREFIX) SCAL VEC VABI_PREFIX
+#include "llvm/Analysis/VecFuncs.def"
+    , {
 #include "llvm/Analysis/VecFuncs.def"
+      });
 #undef TLI_DEFINE_DARWIN_LIBSYSTEM_M_VECFUNCS
-};
 
-static const VecDesc VecFuncs_LIBMVEC_X86[] = {
 #define TLI_DEFINE_LIBMVEC_X86_VECFUNCS
+static constexpr auto VecFuncs_LIBMVEC_X86 = VecDescBuilder::build(
+#define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, VABI_PREFIX) SCAL VEC VABI_PREFIX
+#include "llvm/Analysis/VecFuncs.def"
+    , {
 #include "llvm/Analysis/VecFuncs.def"
+      });
 #undef TLI_DEFINE_LIBMVEC_X86_VECFUNCS
-};
 
-static const VecDesc VecFuncs_LIBMVEC_AARCH64[] = {
 #define TLI_DEFINE_LIBMVEC_AARCH64_VECFUNCS
+static constexpr auto VecFuncs_LIBMVEC_AARCH64 = VecDescBuilder::build(
+#define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, MASK, VABI_PREFIX, CC)               \
+  SCAL VEC VABI_PREFIX
+#include "llvm/Analysis/VecFuncs.def"
+    , {
 #define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, MASK, VABI_PREFIX, CC)               \
   {SCAL, VEC, VF, MASK, VABI_PREFIX, CC},
 #include "llvm/Analysis/VecFuncs.def"
+      });
 #undef TLI_DEFINE_LIBMVEC_AARCH64_VECFUNCS
-};
 
-static const VecDesc VecFuncs_MASSV[] = {
 #define TLI_DEFINE_MASSV_VECFUNCS
+static constexpr auto VecFuncs_MASSV = VecDescBuilder::build(
+#define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, VABI_PREFIX) SCAL VEC VABI_PREFIX
+#include "llvm/Analysis/VecFuncs.def"
+    , {
 #include "llvm/Analysis/VecFuncs.def"
+      });
 #undef TLI_DEFINE_MASSV_VECFUNCS
-};
 
-static const VecDesc VecFuncs_SVML[] = {
 #define TLI_DEFINE_SVML_VECFUNCS
+static constexpr auto VecFuncs_SVML = VecDescBuilder::build(
+#define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, VABI_PREFIX) SCAL VEC VABI_PREFIX
+#include "llvm/Analysis/VecFuncs.def"
+    , {
 #include "llvm/Analysis/VecFuncs.def"
+      });
 #undef TLI_DEFINE_SVML_VECFUNCS
-};
 
-static const VecDesc VecFuncs_SLEEFGNUABI_VF2[] = {
 #define TLI_DEFINE_SLEEFGNUABI_VF2_VECFUNCS
+static constexpr auto VecFuncs_SLEEFGNUABI_VF2 = VecDescBuilder::build(
+#define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, VABI_PREFIX) SCAL VEC VABI_PREFIX
+#include "llvm/Analysis/VecFuncs.def"
+    , {
 #define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, VABI_PREFIX)                         \
   {SCAL, VEC, VF, /* MASK = */ false, VABI_PREFIX, /* CC = */ std::nullopt},
 #include "llvm/Analysis/VecFuncs.def"
+      });
 #undef TLI_DEFINE_SLEEFGNUABI_VF2_VECFUNCS
-};
-static const VecDesc VecFuncs_SLEEFGNUABI_VF4[] = {
 #define TLI_DEFINE_SLEEFGNUABI_VF4_VECFUNCS
+static constexpr auto VecFuncs_SLEEFGNUABI_VF4 = VecDescBuilder::build(
+#define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, VABI_PREFIX) SCAL VEC VABI_PREFIX
+#include "llvm/Analysis/VecFuncs.def"
+    , {
 #define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, VABI_PREFIX)                         \
   {SCAL, VEC, VF, /* MASK = */ false, VABI_PREFIX, /* CC = */ std::nullopt},
 #include "llvm/Analysis/VecFuncs.def"
+      });
 #undef TLI_DEFINE_SLEEFGNUABI_VF4_VECFUNCS
-};
-static const VecDesc VecFuncs_SLEEFGNUABI_VFScalable[] = {
 #define TLI_DEFINE_SLEEFGNUABI_SCALABLE_VECFUNCS
+static constexpr auto VecFuncs_SLEEFGNUABI_VFScalable = VecDescBuilder::build(
+#define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, MASK, VABI_PREFIX)                   \
+  SCAL VEC VABI_PREFIX
+#include "llvm/Analysis/VecFuncs.def"
+    , {
 #define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, MASK, VABI_PREFIX)                   \
   {SCAL, VEC, VF, MASK, VABI_PREFIX, /* CC = */ std::nullopt},
 #include "llvm/Analysis/VecFuncs.def"
+      });
 #undef TLI_DEFINE_SLEEFGNUABI_SCALABLE_VECFUNCS
-};
 
-static const VecDesc VecFuncs_SLEEFGNUABI_VFScalableRISCV[] = {
 #define TLI_DEFINE_SLEEFGNUABI_SCALABLE_VECFUNCS_RISCV
+static constexpr auto VecFuncs_SLEEFGNUABI_VFScalableRISCV =
+    VecDescBuilder::build(
+#define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, MASK, VABI_PREFIX)                   \
+  SCAL VEC VABI_PREFIX
+#include "llvm/Analysis/VecFuncs.def"
+        , {
 #define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, MASK, VABI_PREFIX)                   \
   {SCAL, VEC, VF, MASK, VABI_PREFIX, /* CC = */ std::nullopt},
 #include "llvm/Analysis/VecFuncs.def"
+          });
 #undef TLI_DEFINE_SLEEFGNUABI_SCALABLE_VECFUNCS_RISCV
-};
 
-static const VecDesc VecFuncs_ArmPL[] = {
 #define TLI_DEFINE_ARMPL_VECFUNCS
+static constexpr auto VecFuncs_ArmPL = VecDescBuilder::build(
+#define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, MASK, VABI_PREFIX, CC)               \
+  SCAL VEC VABI_PREFIX
+#include "llvm/Analysis/VecFuncs.def"
+    , {
 #define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, MASK, VABI_PREFIX, CC)               \
   {SCAL, VEC, VF, MASK, VABI_PREFIX, CC},
 #include "llvm/Analysis/VecFuncs.def"
+      });
 #undef TLI_DEFINE_ARMPL_VECFUNCS
-};
 
-const VecDesc VecFuncs_AMDLIBM[] = {
 #define TLI_DEFINE_AMDLIBM_VECFUNCS
+static constexpr auto VecFuncs_AMDLIBM = VecDescBuilder::build(
+#define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, MASK, VABI_PREFIX)                   \
+  SCAL VEC VABI_PREFIX
+#include "llvm/Analysis/VecFuncs.def"
+    , {
 #define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, MASK, VABI_PREFIX)                   \
   {SCAL, VEC, VF, MASK, VABI_PREFIX, /* CC = */ std::nullopt},
 #include "llvm/Analysis/VecFuncs.def"
+      });
 #undef TLI_DEFINE_AMDLIBM_VECFUNCS
-};
 
 void TargetLibraryInfoImpl::addVectorizableFunctionsFromVecLib(
     enum VectorLibrary VecLib, const llvm::Triple &TargetTriple) {
@@ -1402,9 +1492,8 @@ bool TargetLibraryInfoImpl::isFunctionVectorizable(StringRef funcName) const {
   if (funcName.empty())
     return false;
 
-  std::vector<VecDesc>::const_iterator I =
-      llvm::lower_bound(VectorDescs, funcName, compareWithScalarFnName);
-  return I != VectorDescs.end() && StringRef(I->getScalarFnName()) == funcName;
+  auto I = llvm::lower_bound(VectorDescs, funcName, compareWithScalarFnName);
+  return I != VectorDescs.end() && (*I)->getScalarFnName() == funcName;
 }
 
 StringRef TargetLibraryInfoImpl::getVectorizedFunction(StringRef F,
@@ -1422,11 +1511,10 @@ TargetLibraryInfoImpl::getVectorMappingInfo(StringRef F, const ElementCount &VF,
   F = sanitizeFunctionName(F);
   if (F.empty())
     return nullptr;
-  std::vector<VecDesc>::const_iterator I =
-      llvm::lower_bound(VectorDescs, F, compareWithScalarFnName);
-  while (I != VectorDescs.end() && StringRef(I->getScalarFnName()) == F) {
-    if ((I->getVectorizationFactor() == VF) && (I->isMasked() == Masked))
-      return &(*I);
+  auto I = llvm::lower_bound(VectorDescs, F, compareWithScalarFnName);
+  while (I != VectorDescs.end() && (*I)->getScalarFnName() == F) {
+    if (((*I)->getVectorizationFactor() == VF) && ((*I)->isMasked() == Masked))
+      return *I;
     ++I;
   }
   return nullptr;
@@ -1493,13 +1581,12 @@ void TargetLibraryInfoImpl::getWidestVF(StringRef ScalarF,
   if (ScalarF.empty())
     return;
 
-  std::vector<VecDesc>::const_iterator I =
-      llvm::lower_bound(VectorDescs, ScalarF, compareWithScalarFnName);
-  while (I != VectorDescs.end() && StringRef(I->getScalarFnName()) == ScalarF) {
+  auto I = llvm::lower_bound(VectorDescs, ScalarF, compareWithScalarFnName);
+  while (I != VectorDescs.end() && (*I)->getScalarFnName() == ScalarF) {
     ElementCount *VF =
-        I->getVectorizationFactor().isScalable() ? &ScalableVF : &FixedVF;
-    if (ElementCount::isKnownGT(I->getVectorizationFactor(), *VF))
-      *VF = I->getVectorizationFactor();
+        (*I)->getVectorizationFactor().isScalable() ? &ScalableVF : &FixedVF;
+    if (ElementCount::isKnownGT((*I)->getVectorizationFactor(), *VF))
+      *VF = (*I)->getVectorizationFactor();
     ++I;
   }
 }
diff --git a/llvm/unittests/Analysis/CMakeLists.txt b/llvm/unittests/Analysis/CMakeLists.txt
index 50bf4539e7984..70e5f328f2e4c 100644
--- a/llvm/unittests/Analysis/CMakeLists.txt
+++ b/llvm/unittests/Analysis/CMakeLists.txt
@@ -49,7 +49,6 @@ set(ANALYSIS_TEST_SOURCES
   PluginInlineAdvisorAnalysisTest.cpp
   PluginInlineOrderAnalysisTest.cpp
   ProfileSummaryInfoTest.cpp
-  ReplaceWithVecLibTest.cpp
   ScalarEvolutionTest.cpp
   SparsePropagation.cpp
   TargetLibraryInfoTest.cpp
diff --git a/llvm/unittests/Analysis/ReplaceWithVecLibTest.cpp b/llvm/unittests/Analysis/ReplaceWithVecLibTest.cpp
deleted file mode 100644
index 31e0263ad64d7..0000000000000
--- a/llvm/unittests/Analysis/ReplaceWithVecLibTest.cpp
+++ /dev/null
@@ -1,115 +0,0 @@
-//===--- ReplaceWithVecLibTest.cpp - replace-with-veclib unit tests -------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/CodeGen/ReplaceWithVeclib.h"
-#include "llvm/Analysis/TargetLibraryInfo.h"
-#include "llvm/AsmParser/Parser.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/Module.h"
-#include "llvm/Passes/PassBuilder.h"
-#include "llvm/Support/SourceMgr.h"
-#include "gtest/gtest.h"
-
-using namespace llvm;
-
-/// NOTE: Assertions must be enabled for these tests to run.
-#ifndef NDEBUG
-
-namespace {
-
-static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
-  SMDiagnostic Err;
-  std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
-  if (!Mod)
-    Err.print("ReplaceWithVecLibTest", errs());
-  return Mod;
-}
-
-/// Runs ReplaceWithVecLib with different TLIIs that have custom VecDescs. This
-/// allows checking that the pass won't crash when the function to replace (from
-/// the input IR) does not match the replacement function (derived from the
-/// VecDesc mapping).
-///
-class ReplaceWithVecLibTest : public ::testing::Test {
-
-  std::string getLastLine(std::string Out) {
-    // remove any trailing '\n'
-    if (!Out.empty() && *(Out.cend() - 1) == '\n')
-      Out.pop_back();
-
-    size_t LastNL = Out.find_last_of('\n');
-    return (LastNL == std::string::npos) ? Out : Out.substr(LastNL + 1);
-  }
-
-protected:
-  LLVMContext Ctx;
-
-  /// Creates TLII using the given \p VD, and then runs the ReplaceWithVeclib
-  /// pass. The pass should not crash even when the replacement function
-  /// (derived from the \p VD mapping) does not match the function to be
-  /// replaced (from the input \p IR).
-  ///
-  /// \returns the last line of the standard error to be compared for
-  /// correctness.
-  std::string run(const VecDesc &VD, const char *IR) {
-    // Create TLII and register it with FAM so it's preserved when
-    // ReplaceWithVeclib pass runs.
-    TargetLibraryInfoImpl TLII = TargetLibraryInfoImpl(Triple());
-    TLII.addVectorizableFunctions({VD});
-    FunctionAnalysisManager FAM;
-    FAM.registerPass([&TLII]() { return TargetLibraryAnalysis(TLII); });
-
-    // Register and run the pass on the 'foo' function from the input IR.
-    FunctionPassManager FPM;
-    FPM.addPass(ReplaceWithVeclib());
-    std::unique_ptr<Module> M = parseIR(Ctx, IR);
-    PassBuilder PB;
-    PB.registerFunctionAnalyses(FAM);
-
-    // Enable debugging and capture std error
-    bool DebugFlagPrev = llvm::DebugFlag;
-    llvm::DebugFlag = true;
-    testing::internal::CaptureStderr();
-    FPM.run(*M->getFunction("foo"), FAM);
-    llvm::DebugFlag = DebugFlagPrev;
-    return getLastLine(testing::internal::GetCapturedStderr());
-  }
-};
-
-} // end anonymous namespace
-
-static const char *IR = R"IR(
-define <vscale x 4 x float> @foo(<vscale x 4 x float> %in){
-  %call = call <vscale x 4 x float> @llvm.powi.f32.i32(<vscale x 4 x float> %in, i32 3)
-  ret <vscale x 4 x float> %call
-}
-
-declare <vscale x 4 x float> @llvm.powi.f32.i32(<vscale x 4 x float>, i32) #0
-)IR";
-
-// The VFABI prefix in TLI describes signature which is matching the powi
-// intrinsic declaration.
-TEST_F(ReplaceWithVecLibTest, TestValidMapping) {
-  VecDesc CorrectVD = {"llvm.powi.f32.i32", "_ZGVsMxvu_powi",
-                       ElementCount::getScalable(4), /*Masked*/ true,
-                       "_ZGVsMxvu", /* CC = */ std::nullopt};
-  EXPECT_EQ(run(CorrectVD, IR),
-            "Intrinsic calls replaced with vector libraries: 1");
-}
-
-// The VFABI prefix in TLI describes signature which is not matching the powi
-// intrinsic declaration.
-TEST_F(ReplaceWithVecLibTest, TestInvalidMapping) {
-  VecDesc IncorrectVD = {"llvm.powi.f32.i32", "_ZGVsMxvv_powi",
-                         ElementCount::getScalable(4), /*Masked*/ true,
-                         "_ZGVsMxvv", /* CC = */ std::nullopt};
-  EXPECT_EQ(run(IncorrectVD, IR),
-            "replace-with-veclib: Will not replace: llvm.powi.f32.i32. Wrong "
-            "type at index 1: i32");
-}
-#endif

>From 3248c016d8c6ec9bb2abda0a614a9b20d4e98b74 Mon Sep 17 00:00:00 2001
From: Alexis Engelke <engelke at in.tum.de>
Date: Tue, 2 Jun 2026 15:45:26 +0000
Subject: [PATCH 2/2] better/less hacky implementation

Created using spr 1.3.8-wip
---
 .../include/llvm/Analysis/TargetLibraryInfo.h |  8 +-
 llvm/lib/Analysis/TargetLibraryInfo.cpp       | 75 ++++++++++---------
 2 files changed, 41 insertions(+), 42 deletions(-)

diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.h b/llvm/include/llvm/Analysis/TargetLibraryInfo.h
index 6450a8a05f8c0..ff72355bb851e 100644
--- a/llvm/include/llvm/Analysis/TargetLibraryInfo.h
+++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.h
@@ -43,7 +43,7 @@ template <typename T> class ArrayRef;
 /// <scalarname> = the name of the scalar function.
 /// <vectorname> = the name of the vector function.
 class VecDesc {
-  friend struct VecDescBuilder;
+  template <size_t, size_t> friend struct VecDescTable;
 
   // String offsets are relative to the this pointer.
   uint16_t ScalarFnNameOff = 0;
@@ -58,11 +58,9 @@ class VecDesc {
 
   constexpr VecDesc() {}
 
-  // Due to the relative string offsets, VecDesc is neither copyable nor
-  // movable. The move constructor has to exist to allow assignment to a
-  // variable.
+  // Due to the relative string offsets, VecDesc is not copyable/movable.
   VecDesc(const VecDesc &) = delete;
-  VecDesc(VecDesc &&) = default;
+  VecDesc(VecDesc &&) = delete;
 
 public:
   StringRef getScalarFnName() const {
diff --git a/llvm/lib/Analysis/TargetLibraryInfo.cpp b/llvm/lib/Analysis/TargetLibraryInfo.cpp
index 701c84dc99ce3..bd0cd8ba1085f 100644
--- a/llvm/lib/Analysis/TargetLibraryInfo.cpp
+++ b/llvm/lib/Analysis/TargetLibraryInfo.cpp
@@ -1257,42 +1257,44 @@ struct VecDescData {
 };
 
 namespace llvm {
-struct VecDescBuilder {
-  template <size_t M, size_t N>
-  static constexpr auto build(const char (&StrTab)[M],
-                              const VecDescData (&Data)[N]) {
-    struct {
-      VecDesc Descs[N];
-      char StringTable[M];
-
-      operator ArrayRef<VecDesc>() const { return ArrayRef(Descs, N); }
-    } Ret{};
+template <size_t M, size_t N> struct VecDescTable {
+  VecDesc Descs[N];
+  char StringTable[M];
+
+  constexpr VecDescTable(const char (&StrTab)[M],
+                         const VecDescData (&Data)[N]) {
     for (size_t i = 0; i != M; i++)
-      Ret.StringTable[i] = StrTab[i];
-    size_t Off = offsetof(decltype(Ret), StringTable);
+      StringTable[i] = StrTab[i];
+    size_t Off = offsetof(VecDescTable, StringTable);
     for (size_t i = 0; i != N; i++) {
       assert(Off < UINT16_MAX);
-      Ret.Descs[i].ScalarFnNameOff = Off;
+      Descs[i].ScalarFnNameOff = Off;
       Off += Data[i].ScalarFnName.size();
-      Ret.Descs[i].ScalarFnNameSize = Data[i].ScalarFnName.size();
-      Ret.Descs[i].VectorFnNameOff = Off;
+      Descs[i].ScalarFnNameSize = Data[i].ScalarFnName.size();
+      Descs[i].VectorFnNameOff = Off;
       Off += Data[i].VectorFnName.size();
-      Ret.Descs[i].VectorFnNameSize = Data[i].VectorFnName.size();
-      Ret.Descs[i].VectorizationFactor = Data[i].VectorizationFactor;
-      Ret.Descs[i].Masked = Data[i].Masked;
-      Ret.Descs[i].VABIPrefixOff = Off;
+      Descs[i].VectorFnNameSize = Data[i].VectorFnName.size();
+      Descs[i].VectorizationFactor = Data[i].VectorizationFactor;
+      Descs[i].Masked = Data[i].Masked;
+      Descs[i].VABIPrefixOff = Off;
       Off += Data[i].VABIPrefix.size();
-      Ret.Descs[i].VABIPrefixSize = Data[i].VABIPrefix.size();
-      Ret.Descs[i].CC = Data[i].CC;
+      Descs[i].VABIPrefixSize = Data[i].VABIPrefix.size();
+      Descs[i].CC = Data[i].CC;
       Off -= sizeof(VecDesc);
     }
-    return Ret;
   }
+
+  operator ArrayRef<VecDesc>() const { return ArrayRef(Descs, N); }
 };
+
+// Silence warning on possibly unintended CTAD.
+template <size_t N, size_t M>
+VecDescTable(const char (&)[M], const VecDescData (&)[N]) -> VecDescTable<M, N>;
+
 } // namespace llvm
 
 #define TLI_DEFINE_ACCELERATE_VECFUNCS
-static constexpr auto VecFuncs_Accelerate = VecDescBuilder::build(
+static constexpr VecDescTable VecFuncs_Accelerate(
 #define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, VABI_PREFIX) SCAL VEC VABI_PREFIX
 #include "llvm/Analysis/VecFuncs.def"
     , {
@@ -1301,7 +1303,7 @@ static constexpr auto VecFuncs_Accelerate = VecDescBuilder::build(
 #undef TLI_DEFINE_ACCELERATE_VECFUNCS
 
 #define TLI_DEFINE_DARWIN_LIBSYSTEM_M_VECFUNCS
-static constexpr auto VecFuncs_DarwinLibSystemM = VecDescBuilder::build(
+static constexpr VecDescTable VecFuncs_DarwinLibSystemM(
 #define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, VABI_PREFIX) SCAL VEC VABI_PREFIX
 #include "llvm/Analysis/VecFuncs.def"
     , {
@@ -1310,7 +1312,7 @@ static constexpr auto VecFuncs_DarwinLibSystemM = VecDescBuilder::build(
 #undef TLI_DEFINE_DARWIN_LIBSYSTEM_M_VECFUNCS
 
 #define TLI_DEFINE_LIBMVEC_X86_VECFUNCS
-static constexpr auto VecFuncs_LIBMVEC_X86 = VecDescBuilder::build(
+static constexpr VecDescTable VecFuncs_LIBMVEC_X86(
 #define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, VABI_PREFIX) SCAL VEC VABI_PREFIX
 #include "llvm/Analysis/VecFuncs.def"
     , {
@@ -1319,7 +1321,7 @@ static constexpr auto VecFuncs_LIBMVEC_X86 = VecDescBuilder::build(
 #undef TLI_DEFINE_LIBMVEC_X86_VECFUNCS
 
 #define TLI_DEFINE_LIBMVEC_AARCH64_VECFUNCS
-static constexpr auto VecFuncs_LIBMVEC_AARCH64 = VecDescBuilder::build(
+static constexpr VecDescTable VecFuncs_LIBMVEC_AARCH64(
 #define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, MASK, VABI_PREFIX, CC)               \
   SCAL VEC VABI_PREFIX
 #include "llvm/Analysis/VecFuncs.def"
@@ -1331,7 +1333,7 @@ static constexpr auto VecFuncs_LIBMVEC_AARCH64 = VecDescBuilder::build(
 #undef TLI_DEFINE_LIBMVEC_AARCH64_VECFUNCS
 
 #define TLI_DEFINE_MASSV_VECFUNCS
-static constexpr auto VecFuncs_MASSV = VecDescBuilder::build(
+static constexpr VecDescTable VecFuncs_MASSV(
 #define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, VABI_PREFIX) SCAL VEC VABI_PREFIX
 #include "llvm/Analysis/VecFuncs.def"
     , {
@@ -1340,7 +1342,7 @@ static constexpr auto VecFuncs_MASSV = VecDescBuilder::build(
 #undef TLI_DEFINE_MASSV_VECFUNCS
 
 #define TLI_DEFINE_SVML_VECFUNCS
-static constexpr auto VecFuncs_SVML = VecDescBuilder::build(
+static constexpr VecDescTable VecFuncs_SVML(
 #define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, VABI_PREFIX) SCAL VEC VABI_PREFIX
 #include "llvm/Analysis/VecFuncs.def"
     , {
@@ -1349,7 +1351,7 @@ static constexpr auto VecFuncs_SVML = VecDescBuilder::build(
 #undef TLI_DEFINE_SVML_VECFUNCS
 
 #define TLI_DEFINE_SLEEFGNUABI_VF2_VECFUNCS
-static constexpr auto VecFuncs_SLEEFGNUABI_VF2 = VecDescBuilder::build(
+static constexpr VecDescTable VecFuncs_SLEEFGNUABI_VF2(
 #define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, VABI_PREFIX) SCAL VEC VABI_PREFIX
 #include "llvm/Analysis/VecFuncs.def"
     , {
@@ -1359,7 +1361,7 @@ static constexpr auto VecFuncs_SLEEFGNUABI_VF2 = VecDescBuilder::build(
       });
 #undef TLI_DEFINE_SLEEFGNUABI_VF2_VECFUNCS
 #define TLI_DEFINE_SLEEFGNUABI_VF4_VECFUNCS
-static constexpr auto VecFuncs_SLEEFGNUABI_VF4 = VecDescBuilder::build(
+static constexpr VecDescTable VecFuncs_SLEEFGNUABI_VF4(
 #define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, VABI_PREFIX) SCAL VEC VABI_PREFIX
 #include "llvm/Analysis/VecFuncs.def"
     , {
@@ -1369,7 +1371,7 @@ static constexpr auto VecFuncs_SLEEFGNUABI_VF4 = VecDescBuilder::build(
       });
 #undef TLI_DEFINE_SLEEFGNUABI_VF4_VECFUNCS
 #define TLI_DEFINE_SLEEFGNUABI_SCALABLE_VECFUNCS
-static constexpr auto VecFuncs_SLEEFGNUABI_VFScalable = VecDescBuilder::build(
+static constexpr VecDescTable VecFuncs_SLEEFGNUABI_VFScalable(
 #define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, MASK, VABI_PREFIX)                   \
   SCAL VEC VABI_PREFIX
 #include "llvm/Analysis/VecFuncs.def"
@@ -1381,20 +1383,19 @@ static constexpr auto VecFuncs_SLEEFGNUABI_VFScalable = VecDescBuilder::build(
 #undef TLI_DEFINE_SLEEFGNUABI_SCALABLE_VECFUNCS
 
 #define TLI_DEFINE_SLEEFGNUABI_SCALABLE_VECFUNCS_RISCV
-static constexpr auto VecFuncs_SLEEFGNUABI_VFScalableRISCV =
-    VecDescBuilder::build(
+static constexpr VecDescTable VecFuncs_SLEEFGNUABI_VFScalableRISCV(
 #define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, MASK, VABI_PREFIX)                   \
   SCAL VEC VABI_PREFIX
 #include "llvm/Analysis/VecFuncs.def"
-        , {
+    , {
 #define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, MASK, VABI_PREFIX)                   \
   {SCAL, VEC, VF, MASK, VABI_PREFIX, /* CC = */ std::nullopt},
 #include "llvm/Analysis/VecFuncs.def"
-          });
+      });
 #undef TLI_DEFINE_SLEEFGNUABI_SCALABLE_VECFUNCS_RISCV
 
 #define TLI_DEFINE_ARMPL_VECFUNCS
-static constexpr auto VecFuncs_ArmPL = VecDescBuilder::build(
+static constexpr VecDescTable VecFuncs_ArmPL(
 #define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, MASK, VABI_PREFIX, CC)               \
   SCAL VEC VABI_PREFIX
 #include "llvm/Analysis/VecFuncs.def"
@@ -1406,7 +1407,7 @@ static constexpr auto VecFuncs_ArmPL = VecDescBuilder::build(
 #undef TLI_DEFINE_ARMPL_VECFUNCS
 
 #define TLI_DEFINE_AMDLIBM_VECFUNCS
-static constexpr auto VecFuncs_AMDLIBM = VecDescBuilder::build(
+static constexpr VecDescTable VecFuncs_AMDLIBM(
 #define TLI_DEFINE_VECFUNC(SCAL, VEC, VF, MASK, VABI_PREFIX)                   \
   SCAL VEC VABI_PREFIX
 #include "llvm/Analysis/VecFuncs.def"



More information about the llvm-commits mailing list