]> granicus.if.org Git - llvm/commitdiff
[SVFS] Vector Function ABI demangling.
authorFrancesco Petrogalli <francesco.petrogalli@arm.com>
Thu, 19 Sep 2019 17:47:32 +0000 (17:47 +0000)
committerFrancesco Petrogalli <francesco.petrogalli@arm.com>
Thu, 19 Sep 2019 17:47:32 +0000 (17:47 +0000)
This patch implements the demangling functionality as described in the
Vector Function ABI. This patch will be used to implement the
SearchVectorFunctionSystem (SVFS) as described in the RFC:

http://lists.llvm.org/pipermail/llvm-dev/2019-June/133484.html

A fuzzer is added to test the demangling utility.

Patch by Sumedh Arani <sumedh.arani@arm.com>

Differential revision: https://reviews.llvm.org/D66024

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@372343 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Analysis/VectorUtils.h
lib/Analysis/CMakeLists.txt
lib/Analysis/VFABIDemangling.cpp [new file with mode: 0644]
tools/vfabi-demangle-fuzzer/CMakeLists.txt [new file with mode: 0644]
tools/vfabi-demangle-fuzzer/vfabi-demangler-fuzzer.cpp [new file with mode: 0644]
unittests/Analysis/CMakeLists.txt
unittests/Analysis/VectorFunctionABITest.cpp [new file with mode: 0644]

index bf0063b3f870d42daab8cd3703b07f61c6ad298d..9811b412569534b38f5e9ee2d2c62768852be4ac 100644 (file)
 
 namespace llvm {
 
+/// Describes the type of Parameters
+enum class VFParamKind {
+  Vector,            // No semantic information.
+  OMP_Linear,        // declare simd linear(i)
+  OMP_LinearRef,     // declare simd linear(ref(i))
+  OMP_LinearVal,     // declare simd linear(val(i))
+  OMP_LinearUVal,    // declare simd linear(uval(i))
+  OMP_LinearPos,     // declare simd linear(i:c) uniform(c)
+  OMP_LinearValPos,  // declare simd linear(val(i:c)) uniform(c)
+  OMP_LinearRefPos,  // declare simd linear(ref(i:c)) uniform(c)
+  OMP_LinearUValPos, // declare simd linear(uval(i:c)) uniform(c
+  OMP_Uniform,       // declare simd uniform(i)
+  GlobalPredicate,   // Global logical predicate that acts on all lanes
+                     // of the input and output mask concurrently. For
+                     // example, it is implied by the `M` token in the
+                     // Vector Function ABI mangled name.
+  Unknown
+};
+
+/// Describes the type of Instruction Set Architecture
+enum class VFISAKind {
+  AdvancedSIMD, // AArch64 Advanced SIMD (NEON)
+  SVE,          // AArch64 Scalable Vector Extension
+  SSE,          // x86 SSE
+  AVX,          // x86 AVX
+  AVX2,         // x86 AVX2
+  AVX512,       // x86 AVX512
+  Unknown       // Unknown ISA
+};
+
+/// Encapsulates information needed to describe a parameter.
+///
+/// The description of the parameter is not linked directly to
+/// OpenMP or any other vector function description. This structure
+/// is extendible to handle other paradigms that describe vector
+/// functions and their parameters.
+struct VFParameter {
+  unsigned ParamPos;         // Parameter Position in Scalar Function.
+  VFParamKind ParamKind;     // Kind of Parameter.
+  int LinearStepOrPos = 0;   // Step or Position of the Parameter.
+  Align Alignment = Align(); // Optional aligment in bytes, defaulted to 1.
+
+  // Comparison operator.
+  bool operator==(const VFParameter &Other) const {
+    return std::tie(ParamPos, ParamKind, LinearStepOrPos, Alignment) ==
+           std::tie(Other.ParamPos, Other.ParamKind, Other.LinearStepOrPos,
+                    Other.Alignment);
+  }
+};
+
+/// Contains the information about the kind of vectorization
+/// available.
+///
+/// This object in independent on the paradigm used to
+/// represent vector functions. in particular, it is not attached to
+/// any target-specific ABI.
+struct VFShape {
+  unsigned VF;     // Vectorization factor.
+  bool IsScalable; // True if the function is a scalable function.
+  VFISAKind ISA;   // Instruction Set Architecture.
+  SmallVector<VFParameter, 8> Parameters; // List of parameter informations.
+  // Comparison operator.
+  bool operator==(const VFShape &Other) const {
+    return std::tie(VF, IsScalable, ISA, Parameters) ==
+           std::tie(Other.VF, Other.IsScalable, Other.ISA, Other.Parameters);
+  }
+};
+
+/// Holds the VFShape for a specific scalar to vector function mapping.
+struct VFInfo {
+  VFShape Shape;        // Classification of the vector function.
+  StringRef ScalarName; // Scalar Function Name.
+  StringRef VectorName; // Vector Function Name associated to this VFInfo.
+
+  // Comparison operator.
+  bool operator==(const VFInfo &Other) const {
+    return std::tie(Shape, ScalarName, VectorName) ==
+           std::tie(Shape, Other.ScalarName, Other.VectorName);
+  }
+};
+
+namespace VFABI {
+/// Function to contruct a VFInfo out of a mangled names in the
+/// following format:
+///
+/// <VFABI_name>{(<redirection>)}
+///
+/// where <VFABI_name> is the name of the vector function, mangled according
+/// to the rules described in the Vector Function ABI of the target vector
+/// extentsion (or <isa> from now on). The <VFABI_name> is in the following
+/// format:
+///
+/// _ZGV<isa><mask><vlen><parameters>_<scalarname>[(<redirection>)]
+///
+/// This methods support demangling rules for the following <isa>:
+///
+/// * AArch64: https://developer.arm.com/docs/101129/latest
+///
+/// * x86 (libmvec): https://sourceware.org/glibc/wiki/libmvec and
+///  https://sourceware.org/glibc/wiki/libmvec?action=AttachFile&do=view&target=VectorABI.txt
+///
+///
+///
+/// \param MangledName -> input string in the format
+/// _ZGV<isa><mask><vlen><parameters>_<scalarname>[(<redirection>)].
+Optional<VFInfo> tryDemangleForVFABI(StringRef MangledName);
+
+/// Retrieve the `VFParamKind` from a string token.
+VFParamKind getVFParamKindFromString(const StringRef Token);
+} // end namespace VFABI
+
 template <typename T> class ArrayRef;
 class DemandedBits;
 class GetElementPtrInst;
index 3d4920e5ead02f5f1036d74c33c1ebef5070059d..5ecc8fe6f735911d14c15538c904c6d39601c6b3 100644 (file)
@@ -97,6 +97,7 @@ add_llvm_library(LLVMAnalysis
   ValueLatticeUtils.cpp
   ValueTracking.cpp
   VectorUtils.cpp
+  VFABIDemangling.cpp
 
   ADDITIONAL_HEADER_DIRS
   ${LLVM_MAIN_INCLUDE_DIR}/llvm/Analysis
diff --git a/lib/Analysis/VFABIDemangling.cpp b/lib/Analysis/VFABIDemangling.cpp
new file mode 100644 (file)
index 0000000..6fd8ae6
--- /dev/null
@@ -0,0 +1,418 @@
+//===- VFABIDemangling.cpp - Vector Function ABI demangling utilities. ---===//
+//
+// 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/Analysis/VectorUtils.h"
+
+using namespace llvm;
+
+namespace {
+/// Utilities for the Vector Function ABI name parser.
+
+/// Return types for the parser functions.
+enum class ParseRet {
+  OK,   // Found.
+  None, // Not found.
+  Error // Syntax error.
+};
+
+/// Extracts the `<isa>` information from the mangled string, and
+/// sets the `ISA` accordingly.
+ParseRet tryParseISA(StringRef &MangledName, VFISAKind &ISA) {
+  if (MangledName.empty())
+    return ParseRet::Error;
+
+  ISA = StringSwitch<VFISAKind>(MangledName.take_front(1))
+            .Case("n", VFISAKind::AdvancedSIMD)
+            .Case("s", VFISAKind::SVE)
+            .Case("b", VFISAKind::SSE)
+            .Case("c", VFISAKind::AVX)
+            .Case("d", VFISAKind::AVX2)
+            .Case("e", VFISAKind::AVX512)
+            .Default(VFISAKind::Unknown);
+
+  MangledName = MangledName.drop_front(1);
+
+  return ParseRet::OK;
+}
+
+/// Extracts the `<mask>` information from the mangled string, and
+/// sets `IsMasked` accordingly. The input string `MangledName` is
+/// left unmodified.
+ParseRet tryParseMask(StringRef &MangledName, bool &IsMasked) {
+  if (MangledName.consume_front("M")) {
+    IsMasked = true;
+    return ParseRet::OK;
+  }
+
+  if (MangledName.consume_front("N")) {
+    IsMasked = false;
+    return ParseRet::OK;
+  }
+
+  return ParseRet::Error;
+}
+
+/// Extract the `<vlen>` information from the mangled string, and
+/// sets `VF` accordingly. A `<vlen> == "x"` token is interpreted as a scalable
+/// vector length. On success, the `<vlen>` token is removed from
+/// the input string `ParseString`.
+///
+ParseRet tryParseVLEN(StringRef &ParseString, unsigned &VF, bool &IsScalable) {
+  if (ParseString.consume_front("x")) {
+    VF = 0;
+    IsScalable = true;
+    return ParseRet::OK;
+  }
+
+  if (ParseString.consumeInteger(10, VF))
+    return ParseRet::Error;
+
+  IsScalable = false;
+  return ParseRet::OK;
+}
+
+/// The function looks for the following strings at the beginning of
+/// the input string `ParseString`:
+///
+///  <token> <number>
+///
+/// On success, it removes the parsed parameter from `ParseString`,
+/// sets `PKind` to the correspondent enum value, sets `Pos` to
+/// <number>, and return success.  On a syntax error, it return a
+/// parsing error. If nothing is parsed, it returns None.
+///
+/// The function expects <token> to be one of "ls", "Rs", "Us" or
+/// "Ls".
+ParseRet tryParseLinearTokenWithRuntimeStep(StringRef &ParseString,
+                                            VFParamKind &PKind, int &Pos,
+                                            const StringRef Token) {
+  if (ParseString.consume_front(Token)) {
+    PKind = VFABI::getVFParamKindFromString(Token);
+    if (ParseString.consumeInteger(10, Pos))
+      return ParseRet::Error;
+    return ParseRet::OK;
+  }
+
+  return ParseRet::None;
+}
+
+/// The function looks for the following stringt at the beginning of
+/// the input string `ParseString`:
+///
+///  <token> <number>
+///
+/// <token> is one of "ls", "Rs", "Us" or "Ls".
+///
+/// On success, it removes the parsed parameter from `ParseString`,
+/// sets `PKind` to the correspondent enum value, sets `StepOrPos` to
+/// <number>, and return success.  On a syntax error, it return a
+/// parsing error. If nothing is parsed, it returns None.
+ParseRet tryParseLinearWithRuntimeStep(StringRef &ParseString,
+                                       VFParamKind &PKind, int &StepOrPos) {
+  ParseRet Ret;
+
+  // "ls" <RuntimeStepPos>
+  Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "ls");
+  if (Ret != ParseRet::None)
+    return Ret;
+
+  // "Rs" <RuntimeStepPos>
+  Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Rs");
+  if (Ret != ParseRet::None)
+    return Ret;
+
+  // "Ls" <RuntimeStepPos>
+  Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Ls");
+  if (Ret != ParseRet::None)
+    return Ret;
+
+  // "Us" <RuntimeStepPos>
+  Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Us");
+  if (Ret != ParseRet::None)
+    return Ret;
+
+  return ParseRet::None;
+}
+
+/// The function looks for the following strings at the beginning of
+/// the input string `ParseString`:
+///
+///  <token> {"n"} <number>
+///
+/// On success, it removes the parsed parameter from `ParseString`,
+/// sets `PKind` to the correspondent enum value, sets `LinearStep` to
+/// <number>, and return success.  On a syntax error, it return a
+/// parsing error. If nothing is parsed, it returns None.
+///
+/// The function expects <token> to be one of "l", "R", "U" or
+/// "L".
+ParseRet tryParseCompileTimeLinearToken(StringRef &ParseString,
+                                        VFParamKind &PKind, int &LinearStep,
+                                        const StringRef Token) {
+  if (ParseString.consume_front(Token)) {
+    PKind = VFABI::getVFParamKindFromString(Token);
+    const bool Negate = ParseString.consume_front("n");
+    if (ParseString.consumeInteger(10, LinearStep))
+      LinearStep = 1;
+    if (Negate)
+      LinearStep *= -1;
+    return ParseRet::OK;
+  }
+
+  return ParseRet::None;
+}
+
+/// The function looks for the following strings at the beginning of
+/// the input string `ParseString`:
+///
+/// ["l" | "R" | "U" | "L"] {"n"} <number>
+///
+/// On success, it removes the parsed parameter from `ParseString`,
+/// sets `PKind` to the correspondent enum value, sets `LinearStep` to
+/// <number>, and return success.  On a syntax error, it return a
+/// parsing error. If nothing is parsed, it returns None.
+ParseRet tryParseLinearWithCompileTimeStep(StringRef &ParseString,
+                                           VFParamKind &PKind, int &StepOrPos) {
+  // "l" {"n"} <CompileTimeStep>
+  if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "l") ==
+      ParseRet::OK)
+    return ParseRet::OK;
+
+  // "R" {"n"} <CompileTimeStep>
+  if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "R") ==
+      ParseRet::OK)
+    return ParseRet::OK;
+
+  // "L" {"n"} <CompileTimeStep>
+  if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "L") ==
+      ParseRet::OK)
+    return ParseRet::OK;
+
+  // "U" {"n"} <CompileTimeStep>
+  if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "U") ==
+      ParseRet::OK)
+    return ParseRet::OK;
+
+  return ParseRet::None;
+}
+
+/// The function looks for the following strings at the beginning of
+/// the input string `ParseString`:
+///
+/// "u" <number>
+///
+/// On success, it removes the parsed parameter from `ParseString`,
+/// sets `PKind` to the correspondent enum value, sets `Pos` to
+/// <number>, and return success.  On a syntax error, it return a
+/// parsing error. If nothing is parsed, it returns None.
+ParseRet tryParseUniform(StringRef &ParseString, VFParamKind &PKind, int &Pos) {
+  // "u" <Pos>
+  const char *UniformToken = "u";
+  if (ParseString.consume_front(UniformToken)) {
+    PKind = VFABI::getVFParamKindFromString(UniformToken);
+    if (ParseString.consumeInteger(10, Pos))
+      return ParseRet::Error;
+
+    return ParseRet::OK;
+  }
+  return ParseRet::None;
+}
+
+/// Looks into the <parameters> part of the mangled name in search
+/// for valid paramaters at the beginning of the string
+/// `ParseString`.
+///
+/// On success, it removes the parsed parameter from `ParseString`,
+/// sets `PKind` to the correspondent enum value, sets `StepOrPos`
+/// accordingly, and return success.  On a syntax error, it return a
+/// parsing error. If nothing is parsed, it returns None.
+ParseRet tryParseParameter(StringRef &ParseString, VFParamKind &PKind,
+                           int &StepOrPos) {
+  if (ParseString.consume_front("v")) {
+    PKind = VFParamKind::Vector;
+    StepOrPos = 0;
+    return ParseRet::OK;
+  }
+
+  const ParseRet HasLinearRuntime =
+      tryParseLinearWithRuntimeStep(ParseString, PKind, StepOrPos);
+  if (HasLinearRuntime != ParseRet::None)
+    return HasLinearRuntime;
+
+  const ParseRet HasLinearCompileTime =
+      tryParseLinearWithCompileTimeStep(ParseString, PKind, StepOrPos);
+  if (HasLinearCompileTime != ParseRet::None)
+    return HasLinearCompileTime;
+
+  const ParseRet HasUniform = tryParseUniform(ParseString, PKind, StepOrPos);
+  if (HasUniform != ParseRet::None)
+    return HasUniform;
+
+  return ParseRet::None;
+}
+
+/// Looks into the <parameters> part of the mangled name in search
+/// of a valid 'aligned' clause. The function should be invoked
+/// after parsing a parameter via `tryParseParameter`.
+///
+/// On success, it removes the parsed parameter from `ParseString`,
+/// sets `PKind` to the correspondent enum value, sets `StepOrPos`
+/// accordingly, and return success.  On a syntax error, it return a
+/// parsing error. If nothing is parsed, it returns None.
+ParseRet tryParseAlign(StringRef &ParseString, Align &Alignment) {
+  uint64_t Val;
+  //    "a" <number>
+  if (ParseString.consume_front("a")) {
+    if (ParseString.consumeInteger(10, Val))
+      return ParseRet::Error;
+
+    if (!isPowerOf2_64(Val))
+      return ParseRet::Error;
+
+    Alignment = Align(Val);
+
+    return ParseRet::OK;
+  }
+
+  return ParseRet::None;
+}
+} // namespace
+
+// Format of the ABI name:
+// _ZGV<isa><mask><vlen><parameters>_<scalarname>[(<redirection>)]
+Optional<VFInfo> VFABI::tryDemangleForVFABI(StringRef MangledName) {
+  // Assume there is no custom name <redirection>, and therefore the
+  // vector name consists of
+  // _ZGV<isa><mask><vlen><parameters>_<scalarname>.
+  StringRef VectorName = MangledName;
+
+  // Parse the fixed size part of the manled name
+  if (!MangledName.consume_front("_ZGV"))
+    return None;
+
+  // Extract ISA. An unknow ISA is also supported, so we accept all
+  // values.
+  VFISAKind ISA;
+  if (tryParseISA(MangledName, ISA) != ParseRet::OK)
+    return None;
+
+  // Extract <mask>.
+  bool IsMasked;
+  if (tryParseMask(MangledName, IsMasked) != ParseRet::OK)
+    return None;
+
+  // Parse the variable size, starting from <vlen>.
+  unsigned VF;
+  bool IsScalable;
+  if (tryParseVLEN(MangledName, VF, IsScalable) != ParseRet::OK)
+    return None;
+
+  // Parse the <parameters>.
+  ParseRet ParamFound;
+  SmallVector<VFParameter, 8> Parameters;
+  do {
+    const unsigned ParameterPos = Parameters.size();
+    VFParamKind PKind;
+    int StepOrPos;
+    ParamFound = tryParseParameter(MangledName, PKind, StepOrPos);
+
+    // Bail off if there is a parsing error in the parsing of the parameter.
+    if (ParamFound == ParseRet::Error)
+      return None;
+
+    if (ParamFound == ParseRet::OK) {
+      Align Alignment;
+      // Look for the alignment token "a <number>".
+      const ParseRet AlignFound = tryParseAlign(MangledName, Alignment);
+      // Bail off if there is a syntax error in the align token.
+      if (AlignFound == ParseRet::Error)
+        return None;
+
+      // Add the parameter.
+      Parameters.push_back({ParameterPos, PKind, StepOrPos, Alignment});
+    }
+  } while (ParamFound == ParseRet::OK);
+
+  // A valid MangledName mus have at least one valid entry in the
+  // <parameters>.
+  if (Parameters.empty())
+    return None;
+
+  // Check for the <scalarname> and the optional <redirection>, which
+  // are separated from the prefix with "_"
+  if (!MangledName.consume_front("_"))
+    return None;
+
+  // The rest of the string must be in the format:
+  // <scalarname>[(<redirection>)]
+  const StringRef ScalarName =
+      MangledName.take_while([](char In) { return In != '('; });
+
+  if (ScalarName.empty())
+    return None;
+
+  // Reduce MangledName to [(<redirection>)].
+  MangledName = MangledName.ltrim(ScalarName);
+  // Find the optional custom name redirection.
+  if (MangledName.consume_front("(")) {
+    if (!MangledName.consume_back(")"))
+      return None;
+    // Update the vector variant with the one specified by the user.
+    VectorName = MangledName;
+    // If the vector name is missing, bail out.
+    if (VectorName.empty())
+      return None;
+  }
+
+  // When <mask> is "M", we need to add a parameter that is used as
+  // global predicate for the function.
+  if (IsMasked) {
+    const unsigned Pos = Parameters.size();
+    Parameters.push_back({Pos, VFParamKind::GlobalPredicate});
+  }
+
+  // Asserts for parameters of type `VFParamKind::GlobalPredicate`, as
+  // prescribed by the Vector Function ABI specifications supported by
+  // this parser:
+  // 1. Uniqueness.
+  // 2. Must be the last in the parameter list.
+  const auto NGlobalPreds = std::count_if(
+      Parameters.begin(), Parameters.end(), [](const VFParameter PK) {
+        return PK.ParamKind == VFParamKind::GlobalPredicate;
+      });
+  assert(NGlobalPreds < 2 && "Cannot have more than one global predicate.");
+  if (NGlobalPreds)
+    assert(Parameters.back().ParamKind == VFParamKind::GlobalPredicate &&
+           "The global predicate must be the last parameter");
+
+  const VFShape Shape({VF, IsScalable, ISA, Parameters});
+  return VFInfo({Shape, ScalarName, VectorName});
+}
+
+VFParamKind VFABI::getVFParamKindFromString(const StringRef Token) {
+  const VFParamKind ParamKind = StringSwitch<VFParamKind>(Token)
+                                    .Case("v", VFParamKind::Vector)
+                                    .Case("l", VFParamKind::OMP_Linear)
+                                    .Case("R", VFParamKind::OMP_LinearRef)
+                                    .Case("L", VFParamKind::OMP_LinearVal)
+                                    .Case("U", VFParamKind::OMP_LinearUVal)
+                                    .Case("ls", VFParamKind::OMP_LinearPos)
+                                    .Case("Ls", VFParamKind::OMP_LinearValPos)
+                                    .Case("Rs", VFParamKind::OMP_LinearRefPos)
+                                    .Case("Us", VFParamKind::OMP_LinearUValPos)
+                                    .Case("u", VFParamKind::OMP_Uniform)
+                                    .Default(VFParamKind::Unknown);
+
+  if (ParamKind != VFParamKind::Unknown)
+    return ParamKind;
+
+  // This function should never be invoked with an invalid input.
+  llvm_unreachable("This fuction should be invoken only on parameters"
+                   " that have a textual representation in the mangled name"
+                   " of the Vector Function ABI");
+}
diff --git a/tools/vfabi-demangle-fuzzer/CMakeLists.txt b/tools/vfabi-demangle-fuzzer/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9083646
--- /dev/null
@@ -0,0 +1,7 @@
+set(LLVM_LINK_COMPONENTS
+  Analysis
+  Support
+)
+add_llvm_fuzzer(vfabi-demangler-fuzzer
+  vfabi-demangler-fuzzer.cpp
+)
diff --git a/tools/vfabi-demangle-fuzzer/vfabi-demangler-fuzzer.cpp b/tools/vfabi-demangle-fuzzer/vfabi-demangler-fuzzer.cpp
new file mode 100644 (file)
index 0000000..13657ef
--- /dev/null
@@ -0,0 +1,26 @@
+//===-- vfabi-demangler-fuzzer.cpp - Fuzzer VFABI using lib/Fuzzer   ------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Build tool to fuzz the demangler for the vector function ABI names.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/VectorUtils.h"
+
+using namespace llvm;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+  const StringRef MangledName((const char *)Data, Size);
+  const auto Info = VFABI::tryDemangleForVFABI(MangledName);
+
+  // Do not optimize away the return value. Inspired by
+  // https://github.com/google/benchmark/blob/master/include/benchmark/benchmark.h#L307-L345
+  asm volatile("" : : "r,m"(Info) : "memory");
+
+  return 0;
+}
index a1858d25b36825f6a1cf21a8c49036d7936a003f..4b4ea416ed8dda14c9c94dfb9219f5d734dfbf4e 100644 (file)
@@ -28,6 +28,7 @@ add_llvm_unittest(AnalysisTests
   PhiValuesTest.cpp
   ProfileSummaryInfoTest.cpp
   ScalarEvolutionTest.cpp
+  VectorFunctionABITest.cpp
   SparsePropagation.cpp
   TargetLibraryInfoTest.cpp
   TBAATest.cpp
diff --git a/unittests/Analysis/VectorFunctionABITest.cpp b/unittests/Analysis/VectorFunctionABITest.cpp
new file mode 100644 (file)
index 0000000..4dbc130
--- /dev/null
@@ -0,0 +1,439 @@
+//===------- VectorFunctionABITest.cpp - VFABI Unittests  ---------===//
+//
+// 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/Analysis/VectorUtils.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+// This test makes sure that the getFromVFABI 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(); }
+
+protected:
+  // Referencies to the parser output field.
+  unsigned &VF = Info.Shape.VF;
+  VFISAKind &ISA = Info.Shape.ISA;
+  SmallVector<VFParameter, 8> &Parameters = Info.Shape.Parameters;
+  StringRef &ScalarName = Info.ScalarName;
+  StringRef &VectorName = Info.VectorName;
+  bool &IsScalable = Info.Shape.IsScalable;
+  // Invoke the parser.
+  bool invokeParser(const StringRef MangledName) {
+    reset();
+    const auto OptInfo = VFABI::tryDemangleForVFABI(MangledName);
+    if (OptInfo.hasValue()) {
+      Info = OptInfo.getValue();
+      return true;
+    }
+
+    return false;
+  }
+  // Checks that 1. the last Parameter in the Shape is of type
+  // VFParamKind::GlobalPredicate and 2. it is the only one of such
+  // type.
+  bool IsMasked() const {
+    const auto NGlobalPreds =
+        std::count_if(Info.Shape.Parameters.begin(),
+                      Info.Shape.Parameters.end(), [](const VFParameter PK) {
+                        return PK.ParamKind == VFParamKind::GlobalPredicate;
+                      });
+    return NGlobalPreds == 1 && Info.Shape.Parameters.back().ParamKind ==
+                                    VFParamKind::GlobalPredicate;
+  }
+};
+} // unnamed namespace
+
+TEST_F(VFABIParserTest, Parse) {
+  EXPECT_TRUE(invokeParser("_ZGVnN2vls2Ls27Us4Rs5l1L10U100R1000_sin"));
+  EXPECT_EQ(VF, (unsigned)2);
+  EXPECT_FALSE(IsMasked());
+  EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
+  EXPECT_FALSE(IsScalable);
+  EXPECT_EQ(Parameters.size(), (unsigned)9);
+  EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector, 0}));
+  EXPECT_EQ(Parameters[1], VFParameter({1, VFParamKind::OMP_LinearPos, 2}));
+  EXPECT_EQ(Parameters[2], VFParameter({2, VFParamKind::OMP_LinearValPos, 27}));
+  EXPECT_EQ(Parameters[3], VFParameter({3, VFParamKind::OMP_LinearUValPos, 4}));
+  EXPECT_EQ(Parameters[4], VFParameter({4, VFParamKind::OMP_LinearRefPos, 5}));
+  EXPECT_EQ(Parameters[5], VFParameter({5, VFParamKind::OMP_Linear, 1}));
+  EXPECT_EQ(Parameters[6], VFParameter({6, VFParamKind::OMP_LinearVal, 10}));
+  EXPECT_EQ(Parameters[7], VFParameter({7, VFParamKind::OMP_LinearUVal, 100}));
+  EXPECT_EQ(Parameters[8], VFParameter({8, VFParamKind::OMP_LinearRef, 1000}));
+  EXPECT_EQ(ScalarName, "sin");
+  EXPECT_EQ(VectorName, "_ZGVnN2vls2Ls27Us4Rs5l1L10U100R1000_sin");
+}
+
+TEST_F(VFABIParserTest, ParseVectorName) {
+  EXPECT_TRUE(invokeParser("_ZGVnN2v_sin(my_v_sin)"));
+  EXPECT_EQ(VF, (unsigned)2);
+  EXPECT_FALSE(IsMasked());
+  EXPECT_FALSE(IsScalable);
+  EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
+  EXPECT_EQ(Parameters.size(), (unsigned)1);
+  EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector, 0}));
+  EXPECT_EQ(ScalarName, "sin");
+  EXPECT_EQ(VectorName, "my_v_sin");
+}
+
+TEST_F(VFABIParserTest, LinearWithCompileTimeNegativeStep) {
+  EXPECT_TRUE(invokeParser("_ZGVnN2ln1Ln10Un100Rn1000_sin"));
+  EXPECT_EQ(VF, (unsigned)2);
+  EXPECT_FALSE(IsMasked());
+  EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
+  EXPECT_FALSE(IsScalable);
+  EXPECT_EQ(Parameters.size(), (unsigned)4);
+  EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::OMP_Linear, -1}));
+  EXPECT_EQ(Parameters[1], VFParameter({1, VFParamKind::OMP_LinearVal, -10}));
+  EXPECT_EQ(Parameters[2], VFParameter({2, VFParamKind::OMP_LinearUVal, -100}));
+  EXPECT_EQ(Parameters[3], VFParameter({3, VFParamKind::OMP_LinearRef, -1000}));
+  EXPECT_EQ(ScalarName, "sin");
+  EXPECT_EQ(VectorName, "_ZGVnN2ln1Ln10Un100Rn1000_sin");
+}
+
+TEST_F(VFABIParserTest, ParseScalableSVE) {
+  EXPECT_TRUE(invokeParser("_ZGVsMxv_sin"));
+  EXPECT_EQ(VF, (unsigned)0);
+  EXPECT_TRUE(IsMasked());
+  EXPECT_TRUE(IsScalable);
+  EXPECT_EQ(ISA, VFISAKind::SVE);
+  EXPECT_EQ(ScalarName, "sin");
+  EXPECT_EQ(VectorName, "_ZGVsMxv_sin");
+}
+
+TEST_F(VFABIParserTest, ParseFixedWidthSVE) {
+  EXPECT_TRUE(invokeParser("_ZGVsM2v_sin"));
+  EXPECT_EQ(VF, (unsigned)2);
+  EXPECT_TRUE(IsMasked());
+  EXPECT_FALSE(IsScalable);
+  EXPECT_EQ(ISA, VFISAKind::SVE);
+  EXPECT_EQ(ScalarName, "sin");
+  EXPECT_EQ(VectorName, "_ZGVsM2v_sin");
+}
+
+TEST_F(VFABIParserTest, NotAVectorFunctionABIName) {
+  // Vector names should start with `_ZGV`.
+  EXPECT_FALSE(invokeParser("ZGVnN2v_sin"));
+}
+
+TEST_F(VFABIParserTest, LinearWithRuntimeStep) {
+  EXPECT_FALSE(invokeParser("_ZGVnN2ls_sin"))
+      << "A number should be present after \"ls\".";
+  EXPECT_TRUE(invokeParser("_ZGVnN2ls2_sin"));
+  EXPECT_FALSE(invokeParser("_ZGVnN2Rs_sin"))
+      << "A number should be present after \"Rs\".";
+  EXPECT_TRUE(invokeParser("_ZGVnN2Rs4_sin"));
+  EXPECT_FALSE(invokeParser("_ZGVnN2Ls_sin"))
+      << "A number should be present after \"Ls\".";
+  EXPECT_TRUE(invokeParser("_ZGVnN2Ls6_sin"));
+  EXPECT_FALSE(invokeParser("_ZGVnN2Us_sin"))
+      << "A number should be present after \"Us\".";
+  EXPECT_TRUE(invokeParser("_ZGVnN2Us8_sin"));
+}
+
+TEST_F(VFABIParserTest, LinearWithoutCompileTime) {
+  EXPECT_TRUE(invokeParser("_ZGVnN3lLRUlnLnRnUn_sin"));
+  EXPECT_EQ(Parameters.size(), (unsigned)8);
+  EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::OMP_Linear, 1}));
+  EXPECT_EQ(Parameters[1], VFParameter({1, VFParamKind::OMP_LinearVal, 1}));
+  EXPECT_EQ(Parameters[2], VFParameter({2, VFParamKind::OMP_LinearRef, 1}));
+  EXPECT_EQ(Parameters[3], VFParameter({3, VFParamKind::OMP_LinearUVal, 1}));
+  EXPECT_EQ(Parameters[4], VFParameter({4, VFParamKind::OMP_Linear, -1}));
+  EXPECT_EQ(Parameters[5], VFParameter({5, VFParamKind::OMP_LinearVal, -1}));
+  EXPECT_EQ(Parameters[6], VFParameter({6, VFParamKind::OMP_LinearRef, -1}));
+  EXPECT_EQ(Parameters[7], VFParameter({7, VFParamKind::OMP_LinearUVal, -1}));
+}
+
+TEST_F(VFABIParserTest, ISA) {
+  EXPECT_TRUE(invokeParser("_ZGVqN2v_sin"));
+  EXPECT_EQ(ISA, VFISAKind::Unknown);
+
+  EXPECT_TRUE(invokeParser("_ZGVnN2v_sin"));
+  EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
+
+  EXPECT_TRUE(invokeParser("_ZGVsN2v_sin"));
+  EXPECT_EQ(ISA, VFISAKind::SVE);
+
+  EXPECT_TRUE(invokeParser("_ZGVbN2v_sin"));
+  EXPECT_EQ(ISA, VFISAKind::SSE);
+
+  EXPECT_TRUE(invokeParser("_ZGVcN2v_sin"));
+  EXPECT_EQ(ISA, VFISAKind::AVX);
+
+  EXPECT_TRUE(invokeParser("_ZGVdN2v_sin"));
+  EXPECT_EQ(ISA, VFISAKind::AVX2);
+
+  EXPECT_TRUE(invokeParser("_ZGVeN2v_sin"));
+  EXPECT_EQ(ISA, VFISAKind::AVX512);
+}
+
+TEST_F(VFABIParserTest, InvalidMask) {
+  EXPECT_FALSE(invokeParser("_ZGVsK2v_sin"));
+}
+
+TEST_F(VFABIParserTest, InvalidParameter) {
+  EXPECT_FALSE(invokeParser("_ZGVsM2vX_sin"));
+}
+
+TEST_F(VFABIParserTest, Align) {
+  EXPECT_TRUE(invokeParser("_ZGVsN2l2a2_sin"));
+  EXPECT_EQ(Parameters.size(), (unsigned)1);
+  EXPECT_EQ(Parameters[0].Alignment, Align(2));
+
+  // Missing alignement value.
+  EXPECT_FALSE(invokeParser("_ZGVsM2l2a_sin"));
+  // Invalid alignment token "x".
+  EXPECT_FALSE(invokeParser("_ZGVsM2l2ax_sin"));
+  // Alignment MUST be associated to a paramater.
+  EXPECT_FALSE(invokeParser("_ZGVsM2a2_sin"));
+  // Alignment must be a power of 2.
+  EXPECT_FALSE(invokeParser("_ZGVsN2l2a0_sin"));
+  EXPECT_TRUE(invokeParser("_ZGVsN2l2a1_sin"));
+  EXPECT_FALSE(invokeParser("_ZGVsN2l2a3_sin"));
+  EXPECT_FALSE(invokeParser("_ZGVsN2l2a6_sin"));
+}
+
+TEST_F(VFABIParserTest, ParseUniform) {
+  EXPECT_TRUE(invokeParser("_ZGVnN2u0_sin"));
+  EXPECT_EQ(VF, (unsigned)2);
+  EXPECT_FALSE(IsMasked());
+  EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
+  EXPECT_FALSE(IsScalable);
+  EXPECT_EQ(Parameters.size(), (unsigned)1);
+  EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::OMP_Uniform, 0}));
+  EXPECT_EQ(ScalarName, "sin");
+  EXPECT_EQ(VectorName, "_ZGVnN2u0_sin");
+
+  EXPECT_FALSE(invokeParser("_ZGVnN2u_sin"));
+  EXPECT_FALSE(invokeParser("_ZGVnN2ul_sin"));
+}
+
+TEST_F(VFABIParserTest, ISAIndependentMangling) {
+  // This test makes sure that the mangling of the parameters in
+  // independent on the <isa> token.
+  const SmallVector<VFParameter, 8> ExpectedParams = {
+      VFParameter({0, VFParamKind::Vector, 0}),
+      VFParameter({1, VFParamKind::OMP_LinearPos, 2}),
+      VFParameter({2, VFParamKind::OMP_LinearValPos, 27}),
+      VFParameter({3, VFParamKind::OMP_LinearUValPos, 4}),
+      VFParameter({4, VFParamKind::OMP_LinearRefPos, 5}),
+      VFParameter({5, VFParamKind::OMP_Linear, 1}),
+      VFParameter({6, VFParamKind::OMP_LinearVal, 10}),
+      VFParameter({7, VFParamKind::OMP_LinearUVal, 100}),
+      VFParameter({8, VFParamKind::OMP_LinearRef, 1000}),
+      VFParameter({9, VFParamKind::OMP_Uniform, 2}),
+  };
+
+#define __COMMON_CHECKS                                                        \
+  do {                                                                         \
+    EXPECT_EQ(VF, (unsigned)2);                                                \
+    EXPECT_FALSE(IsMasked());                                                  \
+    EXPECT_FALSE(IsScalable);                                                  \
+    EXPECT_EQ(Parameters.size(), (unsigned)10);                                \
+    EXPECT_EQ(Parameters, ExpectedParams);                                     \
+    EXPECT_EQ(ScalarName, "sin");                                              \
+  } while (0)
+
+  // Advanced SIMD: <isa> = "n"
+  EXPECT_TRUE(invokeParser("_ZGVnN2vls2Ls27Us4Rs5l1L10U100R1000u2_sin"));
+  EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
+  __COMMON_CHECKS;
+  EXPECT_EQ(VectorName, "_ZGVnN2vls2Ls27Us4Rs5l1L10U100R1000u2_sin");
+
+  // SVE: <isa> = "s"
+  EXPECT_TRUE(invokeParser("_ZGVsN2vls2Ls27Us4Rs5l1L10U100R1000u2_sin"));
+  EXPECT_EQ(ISA, VFISAKind::SVE);
+  __COMMON_CHECKS;
+  EXPECT_EQ(VectorName, "_ZGVsN2vls2Ls27Us4Rs5l1L10U100R1000u2_sin");
+
+  // SSE: <isa> = "b"
+  EXPECT_TRUE(invokeParser("_ZGVbN2vls2Ls27Us4Rs5l1L10U100R1000u2_sin"));
+  EXPECT_EQ(ISA, VFISAKind::SSE);
+  __COMMON_CHECKS;
+  EXPECT_EQ(VectorName, "_ZGVbN2vls2Ls27Us4Rs5l1L10U100R1000u2_sin");
+
+  // AVX: <isa> = "c"
+  EXPECT_TRUE(invokeParser("_ZGVcN2vls2Ls27Us4Rs5l1L10U100R1000u2_sin"));
+  EXPECT_EQ(ISA, VFISAKind::AVX);
+  __COMMON_CHECKS;
+  EXPECT_EQ(VectorName, "_ZGVcN2vls2Ls27Us4Rs5l1L10U100R1000u2_sin");
+
+  // AVX2: <isa> = "d"
+  EXPECT_TRUE(invokeParser("_ZGVdN2vls2Ls27Us4Rs5l1L10U100R1000u2_sin"));
+  EXPECT_EQ(ISA, VFISAKind::AVX2);
+  __COMMON_CHECKS;
+  EXPECT_EQ(VectorName, "_ZGVdN2vls2Ls27Us4Rs5l1L10U100R1000u2_sin");
+
+  // AVX512: <isa> = "e"
+  EXPECT_TRUE(invokeParser("_ZGVeN2vls2Ls27Us4Rs5l1L10U100R1000u2_sin"));
+  EXPECT_EQ(ISA, VFISAKind::AVX512);
+  __COMMON_CHECKS;
+  EXPECT_EQ(VectorName, "_ZGVeN2vls2Ls27Us4Rs5l1L10U100R1000u2_sin");
+
+  // Unknown ISA (randomly using "q"). This test will need update if
+  // some targets decide to use "q" as their ISA token.
+  EXPECT_TRUE(invokeParser("_ZGVqN2vls2Ls27Us4Rs5l1L10U100R1000u2_sin"));
+  EXPECT_EQ(ISA, VFISAKind::Unknown);
+  __COMMON_CHECKS;
+  EXPECT_EQ(VectorName, "_ZGVqN2vls2Ls27Us4Rs5l1L10U100R1000u2_sin");
+
+#undef __COMMON_CHECKS
+}
+
+TEST_F(VFABIParserTest, MissingScalarName) {
+  EXPECT_FALSE(invokeParser("_ZGVnN2v_"));
+}
+
+TEST_F(VFABIParserTest, MissingVectorName) {
+  EXPECT_FALSE(invokeParser("_ZGVnN2v_foo()"));
+}
+
+TEST_F(VFABIParserTest, MissingVectorNameTermination) {
+  EXPECT_FALSE(invokeParser("_ZGVnN2v_foo(bar"));
+}
+
+TEST_F(VFABIParserTest, ParseMaskingNEON) {
+  EXPECT_TRUE(invokeParser("_ZGVnM2v_sin"));
+  EXPECT_EQ(VF, (unsigned)2);
+  EXPECT_TRUE(IsMasked());
+  EXPECT_FALSE(IsScalable);
+  EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
+  EXPECT_EQ(Parameters.size(), (unsigned)2);
+  EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
+  EXPECT_EQ(Parameters[1], VFParameter({1, VFParamKind::GlobalPredicate}));
+  EXPECT_EQ(ScalarName, "sin");
+}
+
+TEST_F(VFABIParserTest, ParseMaskingSVE) {
+  EXPECT_TRUE(invokeParser("_ZGVsM2v_sin"));
+  EXPECT_EQ(VF, (unsigned)2);
+  EXPECT_TRUE(IsMasked());
+  EXPECT_FALSE(IsScalable);
+  EXPECT_EQ(ISA, VFISAKind::SVE);
+  EXPECT_EQ(Parameters.size(), (unsigned)2);
+  EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
+  EXPECT_EQ(Parameters[1], VFParameter({1, VFParamKind::GlobalPredicate}));
+  EXPECT_EQ(ScalarName, "sin");
+}
+
+TEST_F(VFABIParserTest, ParseMaskingSSE) {
+  EXPECT_TRUE(invokeParser("_ZGVbM2v_sin"));
+  EXPECT_EQ(VF, (unsigned)2);
+  EXPECT_TRUE(IsMasked());
+  EXPECT_FALSE(IsScalable);
+  EXPECT_EQ(ISA, VFISAKind::SSE);
+  EXPECT_EQ(Parameters.size(), (unsigned)2);
+  EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
+  EXPECT_EQ(Parameters[1], VFParameter({1, VFParamKind::GlobalPredicate}));
+  EXPECT_EQ(ScalarName, "sin");
+}
+
+TEST_F(VFABIParserTest, ParseMaskingAVX) {
+  EXPECT_TRUE(invokeParser("_ZGVcM2v_sin"));
+  EXPECT_EQ(VF, (unsigned)2);
+  EXPECT_TRUE(IsMasked());
+  EXPECT_FALSE(IsScalable);
+  EXPECT_EQ(ISA, VFISAKind::AVX);
+  EXPECT_EQ(Parameters.size(), (unsigned)2);
+  EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
+  EXPECT_EQ(Parameters[1], VFParameter({1, VFParamKind::GlobalPredicate}));
+  EXPECT_EQ(ScalarName, "sin");
+}
+
+TEST_F(VFABIParserTest, ParseMaskingAVX2) {
+  EXPECT_TRUE(invokeParser("_ZGVdM2v_sin"));
+  EXPECT_EQ(VF, (unsigned)2);
+  EXPECT_TRUE(IsMasked());
+  EXPECT_FALSE(IsScalable);
+  EXPECT_EQ(ISA, VFISAKind::AVX2);
+  EXPECT_EQ(Parameters.size(), (unsigned)2);
+  EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
+  EXPECT_EQ(Parameters[1], VFParameter({1, VFParamKind::GlobalPredicate}));
+  EXPECT_EQ(ScalarName, "sin");
+}
+
+TEST_F(VFABIParserTest, ParseMaskingAVX512) {
+  EXPECT_TRUE(invokeParser("_ZGVeM2v_sin"));
+  EXPECT_EQ(VF, (unsigned)2);
+  EXPECT_TRUE(IsMasked());
+  EXPECT_FALSE(IsScalable);
+  EXPECT_EQ(ISA, VFISAKind::AVX512);
+  EXPECT_EQ(Parameters.size(), (unsigned)2);
+  EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
+  EXPECT_EQ(Parameters[1], VFParameter({1, VFParamKind::GlobalPredicate}));
+  EXPECT_EQ(ScalarName, "sin");
+}