[llvm] 623cff8 - [llvm][VectorUtils] Tweak VFShape for scalable vector functions.

Francesco Petrogalli via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 29 21:55:03 PST 2020


Author: Francesco Petrogalli
Date: 2020-01-30T05:53:56Z
New Revision: 623cff81fef3cc6fb7c619fb7366803864f63dc6

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

LOG: [llvm][VectorUtils] Tweak VFShape for scalable vector functions.

Summary:
This patch makes sure that the field VFShape.VF is greater than zero
when demangling the vector function name of scalable vector functions
encoded in the "vector-function-abi-variant" attribute.

This change is required to be able to provide instances of VFShape
that can be used to query the VFDatabase for the vectorization passes,
as such passes always require a positive value for the Vectorization Factor (VF)
needed by the vectorization process.

It is not possible to extract the value of VFShape.VF from the mangled
name of scalable vector functions, because it is encoded as
`x`. Therefore, the VFABI demangling function has been modified to
extract such information from the IR declaration of the vector
function, under the assumption that _all_ vectors in the signature of
the vector function have the same number of lanes. Such assumption is
valid because it is also assumed by the Vector Function ABI
specifications supported by the demangling function (x86, AArch64, and
LLVM internal one).

The unit tests that demangle scalable names have been modified by
adding the IR module that carries the declaration of the vector
function name being demangled.

In particular, the demangling function fails in the following cases:

1. When the declaration of the scalable vector function is not
    present in the module.

2. When the value of VFSHape.VF is not greater than 0.

Reviewers: jdoerfert, sdesmalen, andwar

Reviewed By: jdoerfert

Subscribers: mgorny, kristof.beyls, hiraditya, llvm-commits

Tags: #llvm

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

Added: 
    

Modified: 
    llvm/include/llvm/Analysis/VectorUtils.h
    llvm/lib/Analysis/VFABIDemangling.cpp
    llvm/lib/Analysis/VectorUtils.cpp
    llvm/lib/Transforms/Utils/ModuleUtils.cpp
    llvm/tools/vfabi-demangle-fuzzer/CMakeLists.txt
    llvm/tools/vfabi-demangle-fuzzer/vfabi-demangler-fuzzer.cpp
    llvm/unittests/Analysis/VectorFunctionABITest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Analysis/VectorUtils.h b/llvm/include/llvm/Analysis/VectorUtils.h
index 8b465ca2983d..f0b0f15d9476 100644
--- a/llvm/include/llvm/Analysis/VectorUtils.h
+++ b/llvm/include/llvm/Analysis/VectorUtils.h
@@ -161,7 +161,12 @@ static constexpr char const *_LLVM_Scalarize_ = "_LLVM_Scalarize_";
 ///
 /// \param MangledName -> input string in the format
 /// _ZGV<isa><mask><vlen><parameters>_<scalarname>[(<redirection>)].
-Optional<VFInfo> tryDemangleForVFABI(StringRef MangledName);
+/// \param M -> Module used to retrive informations about the vector
+/// function that are not possible to retrieve from the mangled
+/// name. At the moment, this parameter is needed only to retrive the
+/// Vectorization Factor of scalable vector functions from their
+/// respective IR declarations.
+Optional<VFInfo> tryDemangleForVFABI(StringRef MangledName, const Module &M);
 
 /// Retrieve the `VFParamKind` from a string token.
 VFParamKind getVFParamKindFromString(const StringRef Token);
@@ -200,7 +205,8 @@ class VFDatabase {
     SmallVector<std::string, 8> ListOfStrings;
     VFABI::getVectorVariantNames(CI, ListOfStrings);
     for (const auto &MangledName : ListOfStrings) {
-      const Optional<VFInfo> Shape = VFABI::tryDemangleForVFABI(MangledName);
+      const Optional<VFInfo> Shape =
+          VFABI::tryDemangleForVFABI(MangledName, *(CI.getModule()));
       // A match is found via scalar and vector names, and also by
       // ensuring that the variant described in the attribute has a
       // corresponding definition or declaration of the vector

diff  --git a/llvm/lib/Analysis/VFABIDemangling.cpp b/llvm/lib/Analysis/VFABIDemangling.cpp
index 84cad1ad1f18..a975e0ff493a 100644
--- a/llvm/lib/Analysis/VFABIDemangling.cpp
+++ b/llvm/lib/Analysis/VFABIDemangling.cpp
@@ -70,6 +70,9 @@ ParseRet tryParseMask(StringRef &MangledName, bool &IsMasked) {
 ///
 ParseRet tryParseVLEN(StringRef &ParseString, unsigned &VF, bool &IsScalable) {
   if (ParseString.consume_front("x")) {
+    // Set VF to 0, to be later adjusted to a value grater than zero
+    // by looking at the signature of the vector function with
+    // `getECFromSignature`.
     VF = 0;
     IsScalable = true;
     return ParseRet::OK;
@@ -78,6 +81,10 @@ ParseRet tryParseVLEN(StringRef &ParseString, unsigned &VF, bool &IsScalable) {
   if (ParseString.consumeInteger(10, VF))
     return ParseRet::Error;
 
+  // The token `0` is invalid for VLEN.
+  if (VF == 0)
+    return ParseRet::Error;
+
   IsScalable = false;
   return ParseRet::OK;
 }
@@ -287,11 +294,50 @@ ParseRet tryParseAlign(StringRef &ParseString, Align &Alignment) {
 
   return ParseRet::None;
 }
+#ifndef NDEBUG
+// Verify the assumtion that all vectors in the signature of a vector
+// function have the same number of elements.
+bool verifyAllVectorsHaveSameWidth(FunctionType *Signature) {
+  SmallVector<VectorType *, 2> VecTys;
+  if (auto *RetTy = dyn_cast<VectorType>(Signature->getReturnType()))
+    VecTys.push_back(RetTy);
+  for (auto *Ty : Signature->params())
+    if (auto *VTy = dyn_cast<VectorType>(Ty))
+      VecTys.push_back(VTy);
+
+  if (VecTys.size() <= 1)
+    return true;
+
+  assert(VecTys.size() > 1 && "Invalid number of elements.");
+  const ElementCount EC = VecTys[0]->getElementCount();
+  return llvm::all_of(
+      llvm::make_range(VecTys.begin() + 1, VecTys.end()),
+      [&EC](VectorType *VTy) { return (EC == VTy->getElementCount()); });
+}
+
+#endif // NDEBUG
+
+// Extract the VectorizationFactor from a given function signature,
+// under the assumtion that all vectors have the same number of
+// elements, i.e. same ElementCount.Min.
+ElementCount getECFromSignature(FunctionType *Signature) {
+  assert(verifyAllVectorsHaveSameWidth(Signature) &&
+         "Invalid vector signature.");
+
+  if (auto *RetTy = dyn_cast<VectorType>(Signature->getReturnType()))
+    return RetTy->getElementCount();
+  for (auto *Ty : Signature->params())
+    if (auto *VTy = dyn_cast<VectorType>(Ty))
+      return VTy->getElementCount();
+
+  return ElementCount(/*Min=*/1, /*Scalable=*/false);
+}
 } // namespace
 
 // Format of the ABI name:
 // _ZGV<isa><mask><vlen><parameters>_<scalarname>[(<redirection>)]
-Optional<VFInfo> VFABI::tryDemangleForVFABI(StringRef MangledName) {
+Optional<VFInfo> VFABI::tryDemangleForVFABI(StringRef MangledName,
+                                            const Module &M) {
   const StringRef OriginalName = MangledName;
   // Assume there is no custom name <redirection>, and therefore the
   // vector name consists of
@@ -402,6 +448,32 @@ Optional<VFInfo> VFABI::tryDemangleForVFABI(StringRef MangledName) {
     assert(Parameters.back().ParamKind == VFParamKind::GlobalPredicate &&
            "The global predicate must be the last parameter");
 
+  // Adjust the VF for scalable signatures. The EC.Min is not encoded
+  // in the name of the function, but it is encoded in the IR
+  // signature of the function. We need to extract this information
+  // because it is needed by the loop vectorizer, which reasons in
+  // terms of VectorizationFactor or ElementCount. In particular, we
+  // need to make sure that the VF field of the VFShape class is never
+  // set to 0.
+  if (IsScalable) {
+    const Function *F = M.getFunction(VectorName);
+    // The declaration of the function must be present in the module
+    // to be able to retrieve its signature.
+    if (!F)
+      return None;
+    const ElementCount EC = getECFromSignature(F->getFunctionType());
+    VF = EC.Min;
+  }
+
+  // Sanity checks.
+  // 1. We don't accept a zero lanes vectorization factor.
+  // 2. We don't accept the demangling if the vector function is not
+  // present in the module.
+  if (VF == 0)
+    return None;
+  if (!M.getFunction(VectorName))
+    return None;
+
   const VFShape Shape({VF, IsScalable, Parameters});
   return VFInfo({Shape, std::string(ScalarName), std::string(VectorName), ISA});
 }

diff  --git a/llvm/lib/Analysis/VectorUtils.cpp b/llvm/lib/Analysis/VectorUtils.cpp
index 8cee54bec049..0fb09e3e0d4f 100644
--- a/llvm/lib/Analysis/VectorUtils.cpp
+++ b/llvm/lib/Analysis/VectorUtils.cpp
@@ -1175,7 +1175,7 @@ void VFABI::getVectorVariantNames(
   for (auto &S : SetVector<StringRef>(ListAttr.begin(), ListAttr.end())) {
 #ifndef NDEBUG
     LLVM_DEBUG(dbgs() << "VFABI: adding mapping '" << S << "'\n");
-    Optional<VFInfo> Info = VFABI::tryDemangleForVFABI(S);
+    Optional<VFInfo> Info = VFABI::tryDemangleForVFABI(S, *(CI.getModule()));
     assert(Info.hasValue() && "Invalid name for a VFABI variant.");
     assert(CI.getModule()->getFunction(Info.getValue().VectorName) &&
            "Vector function is missing.");

diff  --git a/llvm/lib/Transforms/Utils/ModuleUtils.cpp b/llvm/lib/Transforms/Utils/ModuleUtils.cpp
index 51c6450fcc2b..b2e6d981a622 100644
--- a/llvm/lib/Transforms/Utils/ModuleUtils.cpp
+++ b/llvm/lib/Transforms/Utils/ModuleUtils.cpp
@@ -301,7 +301,7 @@ void VFABI::setVectorVariantNames(
 #ifndef NDEBUG
   for (const std::string &VariantMapping : VariantMappings) {
     LLVM_DEBUG(dbgs() << "VFABI: adding mapping '" << VariantMapping << "'\n");
-    Optional<VFInfo> VI = VFABI::tryDemangleForVFABI(VariantMapping);
+    Optional<VFInfo> VI = VFABI::tryDemangleForVFABI(VariantMapping, *M);
     assert(VI.hasValue() && "Cannot add an invalid VFABI name.");
     assert(M->getNamedValue(VI.getValue().VectorName) &&
            "Cannot add variant to attribute: "

diff  --git a/llvm/tools/vfabi-demangle-fuzzer/CMakeLists.txt b/llvm/tools/vfabi-demangle-fuzzer/CMakeLists.txt
index 908364690f5e..353cbedf648a 100644
--- a/llvm/tools/vfabi-demangle-fuzzer/CMakeLists.txt
+++ b/llvm/tools/vfabi-demangle-fuzzer/CMakeLists.txt
@@ -1,5 +1,7 @@
 set(LLVM_LINK_COMPONENTS
   Analysis
+  AsmParser
+  Core
   Support
 )
 add_llvm_fuzzer(vfabi-demangler-fuzzer

diff  --git a/llvm/tools/vfabi-demangle-fuzzer/vfabi-demangler-fuzzer.cpp b/llvm/tools/vfabi-demangle-fuzzer/vfabi-demangler-fuzzer.cpp
index 13657effbbeb..d19629858a42 100644
--- a/llvm/tools/vfabi-demangle-fuzzer/vfabi-demangler-fuzzer.cpp
+++ b/llvm/tools/vfabi-demangle-fuzzer/vfabi-demangler-fuzzer.cpp
@@ -11,12 +11,27 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/Analysis/VectorUtils.h"
+#include "llvm/AsmParser/Parser.h"
 
 using namespace llvm;
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+  LLVMContext Ctx;
+  SMDiagnostic Err;
+  const std::unique_ptr<Module> M =
+      parseAssemblyString("declare i32 @foo(i32 )\n", Err, Ctx);
   const StringRef MangledName((const char *)Data, Size);
-  const auto Info = VFABI::tryDemangleForVFABI(MangledName);
+  // Make sure that whatever symbol the demangler is operating on is
+  // present in the module (the signature is not important). This is
+  // because `tryDemangleForVFABI` fails if the function is not
+  // present. We need to make sure we can even invoke
+  // `getOrInsertFunction` because such method asserts on strings with
+  // zeroes.
+  if (!MangledName.empty() && MangledName.find_first_of(0) == StringRef::npos)
+    M->getOrInsertFunction(
+        MangledName,
+        FunctionType::get(Type::getVoidTy(M->getContext()), false));
+  const auto Info = VFABI::tryDemangleForVFABI(MangledName, *M);
 
   // Do not optimize away the return value. Inspired by
   // https://github.com/google/benchmark/blob/master/include/benchmark/benchmark.h#L307-L345

diff  --git a/llvm/unittests/Analysis/VectorFunctionABITest.cpp b/llvm/unittests/Analysis/VectorFunctionABITest.cpp
index 2e3ddc47caab..e6e1c8afef3c 100644
--- a/llvm/unittests/Analysis/VectorFunctionABITest.cpp
+++ b/llvm/unittests/Analysis/VectorFunctionABITest.cpp
@@ -13,79 +13,34 @@
 
 using namespace llvm;
 
-// This test makes sure that the demangling method succeeds only on
-// valid values of the string.
-TEST(VectorFunctionABITests, OnlyValidNames) {
-  // Incomplete string.
-  EXPECT_FALSE(VFABI::tryDemangleForVFABI("").hasValue());
-  EXPECT_FALSE(VFABI::tryDemangleForVFABI("_ZGV").hasValue());
-  EXPECT_FALSE(VFABI::tryDemangleForVFABI("_ZGVn").hasValue());
-  EXPECT_FALSE(VFABI::tryDemangleForVFABI("_ZGVnN").hasValue());
-  EXPECT_FALSE(VFABI::tryDemangleForVFABI("_ZGVnN2").hasValue());
-  EXPECT_FALSE(VFABI::tryDemangleForVFABI("_ZGVnN2v").hasValue());
-  EXPECT_FALSE(VFABI::tryDemangleForVFABI("_ZGVnN2v_").hasValue());
-  // Missing parameters.
-  EXPECT_FALSE(VFABI::tryDemangleForVFABI("_ZGVnN2_foo").hasValue());
-  // Missing _ZGV prefix.
-  EXPECT_FALSE(VFABI::tryDemangleForVFABI("_ZVnN2v_foo").hasValue());
-  // Missing <isa>.
-  EXPECT_FALSE(VFABI::tryDemangleForVFABI("_ZGVN2v_foo").hasValue());
-  // Missing <mask>.
-  EXPECT_FALSE(VFABI::tryDemangleForVFABI("_ZGVn2v_foo").hasValue());
-  // Missing <vlen>.
-  EXPECT_FALSE(VFABI::tryDemangleForVFABI("_ZGVnNv_foo").hasValue());
-  // Missing <scalarname>.
-  EXPECT_FALSE(VFABI::tryDemangleForVFABI("_ZGVnN2v_").hasValue());
-  // Missing _ separator.
-  EXPECT_FALSE(VFABI::tryDemangleForVFABI("_ZGVnN2vfoo").hasValue());
-  // Missing <vectorname>.
-  EXPECT_FALSE(VFABI::tryDemangleForVFABI("_ZGVnN2v_foo()").hasValue());
-  // Unterminated name.
-  EXPECT_FALSE(VFABI::tryDemangleForVFABI("_ZGVnN2v_foo(bar").hasValue());
-}
-
-TEST(VectorFunctionABITests, ParamListParsing) {
-  // Testing "vl16Ls32R3l"
-  const auto OptVFS = VFABI::tryDemangleForVFABI("_ZGVnN2vl16Ls32R3l_foo");
-  EXPECT_TRUE(OptVFS.hasValue());
-  const VFInfo VFS = OptVFS.getValue();
-  EXPECT_EQ(VFS.Shape.Parameters.size(), (unsigned)5);
-  EXPECT_EQ(VFS.Shape.Parameters[0], VFParameter({0, VFParamKind::Vector, 0}));
-  EXPECT_EQ(VFS.Shape.Parameters[1],
-            VFParameter({1, VFParamKind::OMP_Linear, 16}));
-  EXPECT_EQ(VFS.Shape.Parameters[2],
-            VFParameter({2, VFParamKind::OMP_LinearValPos, 32}));
-  EXPECT_EQ(VFS.Shape.Parameters[3],
-            VFParameter({3, VFParamKind::OMP_LinearRef, 3}));
-  EXPECT_EQ(VFS.Shape.Parameters[4],
-            VFParameter({4, VFParamKind::OMP_Linear, 1}));
-}
-
-TEST(VectorFunctionABITests, ScalarNameAndVectorName) {
-  // Parse Scalar Name
-  const auto A = VFABI::tryDemangleForVFABI("_ZGVnM2v_sin");
-  const auto B = VFABI::tryDemangleForVFABI("_ZGVnM2v_sin(UserFunc)");
-  const auto C = VFABI::tryDemangleForVFABI("_ZGVnM2v___sin_sin_sin");
-  EXPECT_TRUE(A.hasValue());
-  EXPECT_TRUE(B.hasValue());
-  EXPECT_TRUE(C.hasValue());
-  EXPECT_EQ(A.getValue().ScalarName, "sin");
-  EXPECT_EQ(B.getValue().ScalarName, "sin");
-  EXPECT_EQ(C.getValue().ScalarName, "__sin_sin_sin");
-  EXPECT_EQ(A.getValue().VectorName, "_ZGVnM2v_sin");
-  EXPECT_EQ(B.getValue().VectorName, "UserFunc");
-  EXPECT_EQ(C.getValue().VectorName, "_ZGVnM2v___sin_sin_sin");
-}
-
 namespace {
 // Test fixture needed that holds the veariables needed by the parser.
 class VFABIParserTest : public ::testing::Test {
 private:
   // Parser output.
   VFInfo Info;
-  // Reset the parser output references.
-  void reset() { Info = VFInfo(); }
+  // Reset the data needed for the test.
+  void reset(const StringRef Name, const StringRef IRType) {
+    M = parseAssemblyString("declare void @dummy()", Err, Ctx);
+    EXPECT_NE(M.get(), nullptr) << "Loading an invalid module.\n "
+                                << Err.getMessage() << "\n";
+    Type *Ty = parseType(IRType, Err, *(M.get()));
+    FunctionType *FTy = dyn_cast<FunctionType>(Ty);
+    EXPECT_NE(FTy, nullptr) << "Invalid function type string: " << IRType
+                            << "\n"
+                            << Err.getMessage() << "\n";
+    FunctionCallee F = M->getOrInsertFunction(Name, FTy);
+    EXPECT_NE(F.getCallee(), nullptr)
+        << "The function must be present in the module\n";
+    // Reset the VFInfo
+    Info = VFInfo();
+  }
 
+  // Data needed to load the optional IR passed to invokeParser
+  LLVMContext Ctx;
+  SMDiagnostic Err;
+  std::unique_ptr<Module> M;
+  //  CallInst *CI;
 protected:
   // Referencies to the parser output field.
   unsigned &VF = Info.Shape.VF;
@@ -94,10 +49,33 @@ class VFABIParserTest : public ::testing::Test {
   std::string &ScalarName = Info.ScalarName;
   std::string &VectorName = Info.VectorName;
   bool &IsScalable = Info.Shape.IsScalable;
-  // Invoke the parser.
-  bool invokeParser(const StringRef MangledName) {
-    reset();
-    const auto OptInfo = VFABI::tryDemangleForVFABI(MangledName);
+  // Invoke the parser. We need to make sure that a function exist in
+  // the module because the parser fails if such function don't
+  // exists. Every time this method is invoked the state of the test
+  // is reset.
+  //
+  // \p MangledName -> the string the parser has to demangle.
+  //
+  // \p VectorName -> optional vector name that the method needs to
+  // use to create the function in the module if it 
diff ers from the
+  // standard mangled name.
+  //
+  // \p IRType -> FunctionType string to be used for the signature of
+  // the vector function.  The correct signature is needed by the
+  // parser only for scalable functions. For the sake of testing, the
+  // generic fixed-length case can use as signature `void()`.
+  //
+  bool invokeParser(const StringRef MangledName,
+                    const StringRef VectorName = "",
+                    const StringRef IRType = "void()") {
+    StringRef Name = MangledName;
+    if (!VectorName.empty())
+      Name = VectorName;
+    // Reset the VFInfo and the Module to be able to invoke
+    // `invokeParser` multiple times in the same test.
+    reset(Name, IRType);
+
+    const auto OptInfo = VFABI::tryDemangleForVFABI(MangledName, *(M.get()));
     if (OptInfo.hasValue()) {
       Info = OptInfo.getValue();
       return true;
@@ -120,6 +98,67 @@ class VFABIParserTest : public ::testing::Test {
 };
 } // unnamed namespace
 
+// This test makes sure that the demangling method succeeds only on
+// valid values of the string.
+TEST_F(VFABIParserTest, OnlyValidNames) {
+  // Incomplete string.
+  EXPECT_FALSE(invokeParser(""));
+  EXPECT_FALSE(invokeParser("_ZGV"));
+  EXPECT_FALSE(invokeParser("_ZGVn"));
+  EXPECT_FALSE(invokeParser("_ZGVnN"));
+  EXPECT_FALSE(invokeParser("_ZGVnN2"));
+  EXPECT_FALSE(invokeParser("_ZGVnN2v"));
+  EXPECT_FALSE(invokeParser("_ZGVnN2v_"));
+  // Missing parameters.
+  EXPECT_FALSE(invokeParser("_ZGVnN2_foo"));
+  // Missing _ZGV prefix.
+  EXPECT_FALSE(invokeParser("_ZVnN2v_foo"));
+  // Missing <isa>.
+  EXPECT_FALSE(invokeParser("_ZGVN2v_foo"));
+  // Missing <mask>.
+  EXPECT_FALSE(invokeParser("_ZGVn2v_foo"));
+  // Missing <vlen>.
+  EXPECT_FALSE(invokeParser("_ZGVnNv_foo"));
+  // Missing <scalarname>.
+  EXPECT_FALSE(invokeParser("_ZGVnN2v_"));
+  // Missing _ separator.
+  EXPECT_FALSE(invokeParser("_ZGVnN2vfoo"));
+  // Missing <vectorname>. Using `fakename` because the string being
+  // parsed is not a valid function name that `invokeParser` can add.
+  EXPECT_FALSE(invokeParser("_ZGVnN2v_foo()", "fakename"));
+  // Unterminated name. Using `fakename` because the string being
+  // parsed is not a valid function name that `invokeParser` can add.
+  EXPECT_FALSE(invokeParser("_ZGVnN2v_foo(bar", "fakename"));
+}
+
+TEST_F(VFABIParserTest, ParamListParsing) {
+  EXPECT_TRUE(invokeParser("_ZGVnN2vl16Ls32R3l_foo"));
+  EXPECT_EQ(Parameters.size(), (unsigned)5);
+  EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector, 0}));
+  EXPECT_EQ(Parameters[1], VFParameter({1, VFParamKind::OMP_Linear, 16}));
+  EXPECT_EQ(Parameters[2], VFParameter({2, VFParamKind::OMP_LinearValPos, 32}));
+  EXPECT_EQ(Parameters[3], VFParameter({3, VFParamKind::OMP_LinearRef, 3}));
+  EXPECT_EQ(Parameters[4], VFParameter({4, VFParamKind::OMP_Linear, 1}));
+}
+
+TEST_F(VFABIParserTest, ScalarNameAndVectorName_01) {
+  EXPECT_TRUE(invokeParser("_ZGVnM2v_sin"));
+  EXPECT_EQ(ScalarName, "sin");
+  EXPECT_EQ(VectorName, "_ZGVnM2v_sin");
+}
+
+TEST_F(VFABIParserTest, ScalarNameAndVectorName_02) {
+  EXPECT_TRUE(invokeParser("_ZGVnM2v_sin(UserFunc)", "UserFunc"));
+  EXPECT_EQ(ScalarName, "sin");
+  EXPECT_EQ(VectorName, "UserFunc");
+}
+
+TEST_F(VFABIParserTest, ScalarNameAndVectorName_03) {
+  EXPECT_TRUE(invokeParser("_ZGVnM2v___sin_sin_sin"));
+  EXPECT_EQ(ScalarName, "__sin_sin_sin");
+  EXPECT_EQ(VectorName, "_ZGVnM2v___sin_sin_sin");
+}
+
 TEST_F(VFABIParserTest, Parse) {
   EXPECT_TRUE(invokeParser("_ZGVnN2vls2Ls27Us4Rs5l1L10U100R1000_sin"));
   EXPECT_EQ(VF, (unsigned)2);
@@ -141,7 +180,7 @@ TEST_F(VFABIParserTest, Parse) {
 }
 
 TEST_F(VFABIParserTest, ParseVectorName) {
-  EXPECT_TRUE(invokeParser("_ZGVnN2v_sin(my_v_sin)"));
+  EXPECT_TRUE(invokeParser("_ZGVnN2v_sin(my_v_sin)", "my_v_sin"));
   EXPECT_EQ(VF, (unsigned)2);
   EXPECT_FALSE(IsMasked());
   EXPECT_FALSE(IsScalable);
@@ -168,13 +207,15 @@ TEST_F(VFABIParserTest, LinearWithCompileTimeNegativeStep) {
 }
 
 TEST_F(VFABIParserTest, ParseScalableSVE) {
-  EXPECT_TRUE(invokeParser("_ZGVsMxv_sin"));
-  EXPECT_EQ(VF, (unsigned)0);
+  EXPECT_TRUE(invokeParser(
+      "_ZGVsMxv_sin(custom_vg)", "custom_vg",
+      "<vscale x 2 x i32>(<vscale x 2 x i32>, <vscale x 2 x i1>)"));
+  EXPECT_EQ(VF, (unsigned)2);
   EXPECT_TRUE(IsMasked());
   EXPECT_TRUE(IsScalable);
   EXPECT_EQ(ISA, VFISAKind::SVE);
   EXPECT_EQ(ScalarName, "sin");
-  EXPECT_EQ(VectorName, "_ZGVsMxv_sin");
+  EXPECT_EQ(VectorName, "custom_vg");
 }
 
 TEST_F(VFABIParserTest, ParseFixedWidthSVE) {
@@ -245,7 +286,7 @@ TEST_F(VFABIParserTest, ISA) {
 
 TEST_F(VFABIParserTest, LLVM_ISA) {
   EXPECT_FALSE(invokeParser("_ZGV_LLVM_N2v_sin"));
-  EXPECT_TRUE(invokeParser("_ZGV_LLVM_N2v_sin_(vector_name)"));
+  EXPECT_TRUE(invokeParser("_ZGV_LLVM_N2v_sin_(vector_name)", "vector_name"));
   EXPECT_EQ(ISA, VFISAKind::LLVM);
 }
 
@@ -353,8 +394,8 @@ TEST_F(VFABIParserTest, ISAIndependentMangling) {
   EXPECT_EQ(VectorName, "_ZGVeN2vls2Ls27Us4Rs5l1L10U100R1000u2_sin");
 
   // LLVM: <isa> = "_LLVM_" internal vector function.
-  EXPECT_TRUE(
-      invokeParser("_ZGV_LLVM_N2vls2Ls27Us4Rs5l1L10U100R1000u2_sin(vectorf)"));
+  EXPECT_TRUE(invokeParser(
+      "_ZGV_LLVM_N2vls2Ls27Us4Rs5l1L10U100R1000u2_sin(vectorf)", "vectorf"));
   EXPECT_EQ(ISA, VFISAKind::LLVM);
   __COMMON_CHECKS;
   EXPECT_EQ(VectorName, "vectorf");
@@ -454,7 +495,8 @@ TEST_F(VFABIParserTest, ParseMaskingAVX512) {
 }
 
 TEST_F(VFABIParserTest, ParseMaskingLLVM) {
-  EXPECT_TRUE(invokeParser("_ZGV_LLVM_M2v_sin(custom_vector_sin)"));
+  EXPECT_TRUE(invokeParser("_ZGV_LLVM_M2v_sin(custom_vector_sin)",
+                           "custom_vector_sin"));
   EXPECT_EQ(VF, (unsigned)2);
   EXPECT_TRUE(IsMasked());
   EXPECT_FALSE(IsScalable);
@@ -467,8 +509,11 @@ TEST_F(VFABIParserTest, ParseMaskingLLVM) {
 }
 
 TEST_F(VFABIParserTest, ParseScalableMaskingLLVM) {
-  EXPECT_TRUE(invokeParser("_ZGV_LLVM_Mxv_sin(custom_vector_sin)"));
+  EXPECT_TRUE(invokeParser(
+      "_ZGV_LLVM_Mxv_sin(custom_vector_sin)", "custom_vector_sin",
+      "<vscale x 2 x i32> (<vscale x 2 x i32>, <vscale x 2 x i1>)"));
   EXPECT_TRUE(IsMasked());
+  EXPECT_EQ(VF, (unsigned)2);
   EXPECT_TRUE(IsScalable);
   EXPECT_EQ(ISA, VFISAKind::LLVM);
   EXPECT_EQ(Parameters.size(), (unsigned)2);
@@ -479,7 +524,10 @@ TEST_F(VFABIParserTest, ParseScalableMaskingLLVM) {
 }
 
 TEST_F(VFABIParserTest, ParseScalableMaskingLLVMSincos) {
-  EXPECT_TRUE(invokeParser("_ZGV_LLVM_Mxvl8l8_sincos(custom_vector_sincos)"));
+  EXPECT_TRUE(invokeParser("_ZGV_LLVM_Mxvl8l8_sincos(custom_vector_sincos)",
+                           "custom_vector_sincos",
+                           "void(<vscale x 2 x double>, double *, double *)"));
+  EXPECT_EQ(VF, (unsigned)2);
   EXPECT_TRUE(IsMasked());
   EXPECT_TRUE(IsScalable);
   EXPECT_EQ(ISA, VFISAKind::LLVM);
@@ -528,12 +576,13 @@ TEST_F(VFABIAttrTest, Read) {
 
 TEST_F(VFABIParserTest, LLVM_InternalISA) {
   EXPECT_FALSE(invokeParser("_ZGV_LLVM_N2v_sin"));
-  EXPECT_TRUE(invokeParser("_ZGV_LLVM_N2v_sin_(vector_name)"));
+  EXPECT_TRUE(invokeParser("_ZGV_LLVM_N2v_sin_(vector_name)", "vector_name"));
   EXPECT_EQ(ISA, VFISAKind::LLVM);
 }
 
 TEST_F(VFABIParserTest, IntrinsicsInLLVMIsa) {
-  EXPECT_TRUE(invokeParser("_ZGV_LLVM_N4vv_llvm.pow.f32(__svml_powf4)"));
+  EXPECT_TRUE(invokeParser("_ZGV_LLVM_N4vv_llvm.pow.f32(__svml_powf4)",
+                           "__svml_powf4"));
   EXPECT_EQ(VF, (unsigned)4);
   EXPECT_FALSE(IsMasked());
   EXPECT_FALSE(IsScalable);
@@ -543,3 +592,20 @@ TEST_F(VFABIParserTest, IntrinsicsInLLVMIsa) {
   EXPECT_EQ(Parameters[1], VFParameter({1, VFParamKind::Vector}));
   EXPECT_EQ(ScalarName, "llvm.pow.f32");
 }
+
+TEST_F(VFABIParserTest, ParseScalableRequiresDeclaration) {
+  const char *MangledName = "_ZGVsMxv_sin(custom_vg)";
+  // The parser succeds only when the correct function definition of
+  // `custom_vg` is added to the module.
+  EXPECT_FALSE(invokeParser(MangledName));
+  EXPECT_TRUE(invokeParser(
+      MangledName, "custom_vg",
+      "<vscale x 4 x double>(<vscale x 4 x double>, <vscale x 4 x i1>)"));
+}
+
+TEST_F(VFABIParserTest, ZeroIsInvalidVLEN) {
+  EXPECT_FALSE(invokeParser("_ZGVeM0v_sin"));
+  EXPECT_FALSE(invokeParser("_ZGVeN0v_sin"));
+  EXPECT_FALSE(invokeParser("_ZGVsM0v_sin"));
+  EXPECT_FALSE(invokeParser("_ZGVsN0v_sin"));
+}


        


More information about the llvm-commits mailing list