Index: llvm/include/llvm/Analysis/SearchVectorFunctionSystem.h =================================================================== --- /dev/null +++ llvm/include/llvm/Analysis/SearchVectorFunctionSystem.h @@ -0,0 +1,210 @@ +//===- SearchVectorFunctionSystem.h - Search Vector Function System -------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +/// \file +/// This is the interface used for user provided vector functions with the +/// vectorizer. It also contains demangling functionality as specified in the +/// Vector Function ABI specifications. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_SVFS_H +#define LLVM_ANALYSIS_SVFS_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + +// Vector Function ABI +namespace VFABI { + +/// Describes the type of Parameters +enum class ParameterKind { + Vector, // declare simd + 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) + Invalid +}; + +/// Describes the type of Instruction Set Architecture +enum class ISAKind { + ISA_AdvancedSIMD, + ISA_SVE, + ISA_SSE, + ISA_AVX, + ISA_AVX2, + ISA_AVX512, + ISA_Invalid +}; + +/// Encapsulates information needed to describe a parameter +class ParamType { + unsigned ParamPos; // Parameter Position in Scalar Function + ParameterKind ParamKind; // Kind of Parameter + int LinearStepOrPos; // Step or Position of the Parameter + +public: + ParamType(unsigned ParamPos, ParameterKind ParamKind, int LinearStepOrPos) + : ParamPos(ParamPos), ParamKind(ParamKind), + LinearStepOrPos(LinearStepOrPos) {} + + // Constructor for ParameterKind with no step. Eg- ParameterKind::Vector + ParamType(unsigned ParamPos, ParameterKind ParamKind) + : ParamPos(ParamPos), ParamKind(ParamKind), LinearStepOrPos(0) {} + + bool operator==(const ParamType &other) const { + return (ParamPos == other.ParamPos && ParamKind == other.ParamKind && + LinearStepOrPos == other.LinearStepOrPos); + } + + bool isVector() { return ParamKind == ParameterKind::Vector; } + + bool isLinear() { return ParamKind == ParameterKind::OMP_Linear; } + + bool isLinearVal() { return ParamKind == ParameterKind::OMP_LinearVal; } + + bool isLinearRef() { return ParamKind == ParameterKind::OMP_LinearRef; } + + bool isLinearUVal() { return ParamKind == ParameterKind::OMP_LinearUVal; } + + bool isLinearPos() { return ParamKind == ParameterKind::OMP_LinearPos; } + + bool isLinearValPos() { return ParamKind == ParameterKind::OMP_LinearValPos; } + + bool isLinearRefPos() { return ParamKind == ParameterKind::OMP_LinearRefPos; } + + bool isLinearUValPos() { + return ParamKind == ParameterKind::OMP_LinearUValPos; + } + + bool isUniform() { return ParamKind == ParameterKind::OMP_Uniform; } + + int getLinearStepOrPos() { return LinearStepOrPos; } + + void setLinearStepOrPos(int s) { LinearStepOrPos = s; } + + ParameterKind getParameterKind() { return ParamKind; } + + static ParameterKind convertToParameterKind(StringRef kind) { + ParameterKind ParamKind = StringSwitch(kind) + .Case("v", ParameterKind::Vector) + .Case("l", ParameterKind::OMP_Linear) + .Case("R", ParameterKind::OMP_LinearRef) + .Case("L", ParameterKind::OMP_LinearVal) + .Case("U", ParameterKind::OMP_LinearUVal) + .Case("ls", ParameterKind::OMP_LinearPos) + .Case("Ls", ParameterKind::OMP_LinearValPos) + .Case("Rs", ParameterKind::OMP_LinearRefPos) + .Case("Us", ParameterKind::OMP_LinearUValPos) + .Case("u", ParameterKind::OMP_Uniform) + .Default(ParameterKind::Invalid); + + if (ParamKind == ParameterKind::Invalid) + llvm_unreachable("Unexpected Parameter Kind"); + return ParamKind; + } + + unsigned getParamPos() { return ParamPos; } + + void setParamPos(unsigned Position) { ParamPos = Position; } +}; + +/// Contains the information about the kind of vectoriazation available +class VectorFunctionShape { + +public: + unsigned VF; // Vectorization factor + bool IsMasked; // True if Masked + bool IsScalable; // True if Scalable + ISAKind ISA; // Instruction Set Arch + SmallVector Parameters; // List of Parameter Info + StringRef ScalarName; // Scalar Function Name + StringRef VectorName; // Vector ABI Mangled Name + + // Equality checks + bool operator==(const VectorFunctionShape &other) const { + return (VF == other.VF && IsMasked == other.IsMasked && + IsScalable == other.IsScalable && ISA == other.ISA && + Parameters == other.Parameters); + } + + VectorFunctionShape(StringRef MangledName) { + VectorName = MangledName; + assert(parseABISignature(MangledName) && "Incorrect VFABI Signature\n"); + ISA = parseISA(MangledName); + IsMasked = parseIsMasked(MangledName); + VF = parseVF(MangledName); + IsScalable = getIsScalable(); + parseParameters(MangledName); + ScalarName = parseScalarName(MangledName); + } + + /// parses the name of the Vector variant of the function + /// \param MangledName - Mangled name to be parsed + /// \param Result Vector Function name + static StringRef getVectorName(StringRef MangledName); + /// parses the ABI mangled name without redirection specified + /// \param MangledName - Mangled name to be parsed + /// \param Result Vector Function name + static StringRef getPartMangledName(StringRef MangledName); + +private: + /// Checks ABI Signature + /// \param MangledName - Mangled name to be parsed + /// \param Result True if the MangledName follows the ABI signature + bool parseABISignature(StringRef &MangledName); + /// parses Instruction Set Architecture + /// \param MangledName - Mangled name to be parsed + /// \param Result The ISA specified in the mangled name + ISAKind parseISA(StringRef &MangledName); + /// Checks for Mask (inbranch, notinbranch) + /// \param MangledName - Mangled name to be parsed + /// \param Result True if Masked + bool parseIsMasked(StringRef &MangledName); + /// parses vectorization factor + /// \param MangledName - Mangled name to be parsed + /// \param Result Vectorization factor + unsigned parseVF(StringRef &MangledName); + /// parses the name of the Scalar variant of the function + /// \param MangledName - Mangled name to be parsed + /// \param Result Scalar Function name + StringRef parseScalarName(StringRef &MangledName); + /// Parses parameter Information + /// \param ParameterList - Substring of the Mangled Name which captures the + /// info about the parameters \param Parameters Populated SmallVector about + /// Parameter information + void parseParamList(StringRef ParameterList); + /// Checks if it supports scalability + /// \param MangledName - Mangled name to be parsed + /// \param Result True if scalable version exists + bool getIsScalable(); + /// Parses the parameters information + /// \param MangledName - Mangled name to be parsed + /// \param NewRecord - Populate the Parameters in the new record + void parseParameters(StringRef &MangledName); +}; + +} // end namespace VFABI + +} // end namespace llvm + +#endif // LLVM_ANALYSIS_SVFS_H \ No newline at end of file Index: llvm/lib/Analysis/CMakeLists.txt =================================================================== --- llvm/lib/Analysis/CMakeLists.txt +++ llvm/lib/Analysis/CMakeLists.txt @@ -82,6 +82,7 @@ ScalarEvolutionAliasAnalysis.cpp ScalarEvolutionExpander.cpp ScalarEvolutionNormalization.cpp + SearchVectorFunctionSystem.cpp StackSafetyAnalysis.cpp SyncDependenceAnalysis.cpp SyntheticCountsUtils.cpp Index: llvm/lib/Analysis/SearchVectorFunctionSystem.cpp =================================================================== --- /dev/null +++ llvm/lib/Analysis/SearchVectorFunctionSystem.cpp @@ -0,0 +1,224 @@ +//===- SearchVectorFunctionSystem.cpp - Search Vector Function System -----===// +// +// 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/SearchVectorFunctionSystem.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Pass.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +using namespace VFABI; + +bool VectorFunctionShape::parseABISignature(StringRef &MangledName) { + // Capture the ABI Signature value + if (MangledName.startswith("_ZGV")) { + MangledName = MangledName.drop_front(4); + return true; + } + return false; +} + +ISAKind VectorFunctionShape::parseISA(StringRef &MangledName) { + // Capture the ISA value + StringRef ISAValue = MangledName.substr(0, 1); + + ISAKind ISA = StringSwitch(ISAValue) + .Case("n", ISAKind::ISA_AdvancedSIMD) + .Case("s", ISAKind::ISA_SVE) + .Case("b", ISAKind::ISA_SSE) + .Case("c", ISAKind::ISA_AVX) + .Case("d", ISAKind::ISA_AVX2) + .Case("e", ISAKind::ISA_AVX512) + .Default(ISAKind::ISA_Invalid); + + assert(ISA != ISAKind::ISA_Invalid && "Invalid ISA Specified"); + MangledName = MangledName.drop_front(1); + return ISA; +} + +bool VectorFunctionShape::parseIsMasked(StringRef &MangledName) { + // Capture the MASK value + StringRef Mask; + bool IsMasked; + Mask = MangledName.substr(0, 1); + MangledName = MangledName.drop_front(1); + if (this->ISA == ISAKind::ISA_SVE) + return true; + assert((Mask.equals("N") || Mask.equals("M")) && "Invalid masking option"); + IsMasked = Mask.equals("N") ? false : true; + return IsMasked; +} + +unsigned VectorFunctionShape::parseVF(StringRef &MangledName) { + // Capture the VF + // VectorLength can be any positive integer + unsigned VF = 0; + std::size_t Pos; + + Pos = MangledName.find_first_of("vlRLUu_", 0); + if (MangledName.substr(0, 1).equals("x")) { + assert(this->ISA == ISAKind::ISA_SVE && "Incompatible ISA"); + MangledName = MangledName.drop_front(1); + return 0; + } + MangledName.substr(0, Pos).consumeInteger(10, VF); + MangledName = MangledName.drop_front(std::to_string(VF).length()); + return VF; +} + +bool VectorFunctionShape::getIsScalable() { + // Capture if it is Scalable or Not + bool IsSVE = this->ISA == ISAKind::ISA_SVE; + bool IsVFZero = this->VF == 0; + return IsSVE && IsVFZero; +} + +StringRef VectorFunctionShape::parseScalarName(StringRef &MangledName) { + // parse Scalar function name + StringRef ScalarFunctionName; + std::size_t NewPos; + + MangledName = MangledName.drop_front(1); + + NewPos = MangledName.find("(", 0); + // Handles Case: custom vector function name not provided + if (NewPos == StringRef::npos) + NewPos = MangledName.size(); + ScalarFunctionName = MangledName.substr(0, NewPos); + return ScalarFunctionName; +} + +StringRef VectorFunctionShape::getVectorName(StringRef MangledName) { + // parse vector Function Name + StringRef VectorFunctionName; + std::size_t Pos; + std::size_t NewPos; + + Pos = MangledName.find("("); + if (Pos == StringRef::npos) + return MangledName; + Pos++; + NewPos = MangledName.find(")", Pos); + VectorFunctionName = MangledName.substr(Pos, NewPos - Pos); + + return VectorFunctionName; +} + +StringRef VectorFunctionShape::getPartMangledName(StringRef MangledName) { + // Part Mangled Name is Mangled Name without custom vector function + // redirection + StringRef PartMangledName; + std::size_t Pos; + + Pos = MangledName.find("("); + if (Pos == StringRef::npos) + PartMangledName = MangledName; + else + PartMangledName = MangledName.substr(0, Pos); + return PartMangledName; +} + +void VectorFunctionShape::parseParamList(StringRef ParamList) { + std::size_t Pos; // Pos to iterate ParamList + std::size_t NewPos; + + unsigned ParamPos = 0; // parameter position + int LinearStepOrPos; + + Pos = 0; + StringRef ParamKindStr; + ParameterKind ParamKind; + + // Parse the param list and store it to VFS.Parameters + // NewPos - Pos = length of param string + // length of param string = ParamList.str().length() + // TODO: Handle negative numbers for LinearStepOrPos. + // Eg=linear(val(ParamPos):-3)=`Ln3` + while ((NewPos = ParamList.find_first_of("vlRLUu", Pos + 1)) < + (ParamList.str().length())) { + ParamKindStr = ParamList.substr(Pos, 1); + if (ParamList.substr(Pos + 1, 1).equals("s")) { + ParamKindStr = ParamList.substr(Pos, 2); + Pos++; + } + + // +1 to read the LinearStepOrPos value after the param kind + Pos++; + if (NewPos > Pos) { + ParamList.substr(Pos, NewPos - (Pos)).consumeInteger(10, LinearStepOrPos); + assert(std::to_string(LinearStepOrPos).length() == (NewPos - Pos) && + "Incorrect Parameters"); + ParamKind = ParamType::convertToParameterKind(ParamKindStr); + this->Parameters.push_back( + ParamType(ParamPos, ParamKind, LinearStepOrPos)); + } else { + ParamKind = ParamType::convertToParameterKind(ParamKindStr); + ParamType Parameter(ParamPos, ParamKind); + assert((Parameter.isLinear() || Parameter.isLinearRef() || + Parameter.isLinearVal() || Parameter.isVector() || + Parameter.isUniform() || Parameter.isLinearUVal()) && + "Step Not Specified for given ParameterKind"); + // Default LinearStepOrPos value if not specified in ABI signature + if (Parameter.isLinear() || Parameter.isLinearRef() || + Parameter.isLinearVal() || Parameter.isLinearUVal()) { + Parameter.setLinearStepOrPos(1); + } + this->Parameters.push_back(Parameter); + } + ParamPos++; + Pos = NewPos; + } + + // Last param value OR if it is the only parameter + // NewPos is the end of StringRef ParamList + ParamKindStr = ParamList.substr(Pos, 1); + if (ParamList.substr(Pos + 1, 1).equals("s")) { + ParamKindStr = ParamList.substr(Pos, 2); + Pos++; + } + ParamKind = ParamType::convertToParameterKind(ParamKindStr); + // +1 to read the LinearStepOrPos value after the param kind + if ((ParamList.size()) > Pos + 1) { + StringRef StrLinearStepOrPos = + ParamList.substr(Pos + 1, (ParamList.size()) - (Pos + 1)); + StrLinearStepOrPos.consumeInteger(10, LinearStepOrPos); + assert(std::to_string(LinearStepOrPos).length() == + StrLinearStepOrPos.size() && + "Incorrect Parameters"); + this->Parameters.push_back(ParamType(ParamPos, ParamKind, LinearStepOrPos)); + } else { + ParamType Parameter(ParamPos, ParamKind); + assert((Parameter.isLinear() || Parameter.isLinearRef() || + Parameter.isLinearVal() || Parameter.isVector() || + Parameter.isUniform() || Parameter.isLinearUVal()) && + "Step Not Specified for given ParameterKind"); + // Default LinearStepOrPos value if not specified in ABI signature + if (Parameter.isLinear() || Parameter.isLinearRef() || + Parameter.isLinearVal()) { + Parameter.setLinearStepOrPos(1); + } + this->Parameters.push_back(Parameter); + } +} + +void VectorFunctionShape::parseParameters(StringRef &MangledName) { + // Capture the parameters + StringRef ParameterList; + std::size_t NewPos; + + NewPos = MangledName.find("_", 0); + ParameterList = MangledName.substr(0, NewPos); + if (!ParameterList.empty()) + VectorFunctionShape::parseParamList(ParameterList); + MangledName = MangledName.drop_front(ParameterList.size()); +} Index: llvm/tools/vfabi-demangle-fuzzer/CMakeLists.txt =================================================================== --- /dev/null +++ llvm/tools/vfabi-demangle-fuzzer/CMakeLists.txt @@ -0,0 +1,6 @@ +set(LLVM_LINK_COMPONENTS + Analysis +) +add_llvm_fuzzer(vfabi-demangler-fuzzer + vfabi-demangler-fuzzer.cpp +) Index: llvm/tools/vfabi-demangle-fuzzer/vfabi-demangler-fuzzer.cpp =================================================================== --- /dev/null +++ llvm/tools/vfabi-demangle-fuzzer/vfabi-demangler-fuzzer.cpp @@ -0,0 +1,29 @@ +//===-- 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/SearchVectorFunctionSystem.h" + +using namespace llvm; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + const StringRef MangledName((const char *)Data, Size); + const StringRef A = VFABI::VectorFunctionShape::getVectorName(MangledName); + const StringRef B = + VFABI::VectorFunctionShape::getPartMangledName(MangledName); + + // Do not optimize away A and B. Inspired by + // https://github.com/google/benchmark/blob/master/include/benchmark/benchmark.h#L307-L345 + asm volatile("" : : "r,m"(A) : "memory"); + asm volatile("" : : "r,m"(B) : "memory"); + + return 0; +} Index: llvm/unittests/Analysis/CMakeLists.txt =================================================================== --- llvm/unittests/Analysis/CMakeLists.txt +++ llvm/unittests/Analysis/CMakeLists.txt @@ -28,6 +28,7 @@ PhiValuesTest.cpp ProfileSummaryInfoTest.cpp ScalarEvolutionTest.cpp + VectorFunctionABITest.cpp SparsePropagation.cpp TargetLibraryInfoTest.cpp TBAATest.cpp Index: llvm/unittests/Analysis/VectorFunctionABITest.cpp =================================================================== --- /dev/null +++ llvm/unittests/Analysis/VectorFunctionABITest.cpp @@ -0,0 +1,105 @@ +//===------- 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/SearchVectorFunctionSystem.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/raw_ostream.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace VFABI; + +TEST(VectorFunctionABITests, ParamListParsing) { + // Testing "vl16Ls32R3l" + VectorFunctionShape VFS("_ZGVnN2vl16Ls32R3l_foo"); + + EXPECT_EQ(VFS.Parameters[0].getParamPos(), (unsigned)0); + EXPECT_TRUE(VFS.Parameters[0].isVector()); + + EXPECT_EQ(VFS.Parameters[1].getParamPos(), (unsigned)1); + EXPECT_TRUE(VFS.Parameters[1].isLinear()); + EXPECT_EQ(VFS.Parameters[1].getLinearStepOrPos(), 16); + + EXPECT_EQ(VFS.Parameters[2].getParamPos(), (unsigned)2); + EXPECT_TRUE(VFS.Parameters[2].isLinearValPos()); + EXPECT_EQ(VFS.Parameters[2].getLinearStepOrPos(), 32); + + EXPECT_EQ(VFS.Parameters[3].getParamPos(), (unsigned)3); + EXPECT_TRUE(VFS.Parameters[3].isLinearRef()); + EXPECT_EQ(VFS.Parameters[3].getLinearStepOrPos(), 3); + + EXPECT_EQ(VFS.Parameters[4].getParamPos(), (unsigned)4); + EXPECT_TRUE(VFS.Parameters[4].isLinear()); + EXPECT_EQ(VFS.Parameters[4].getLinearStepOrPos(), 1); + + EXPECT_DEATH(VectorFunctionShape("_ZGVnN2vTs_sin"), "Incorrect Parameters"); + + EXPECT_DEATH(VectorFunctionShape("_ZGVnN2vLs_sin"), + "Step Not Specified for given ParameterKind"); +} + +TEST(VectorFunctionABITests, NameDemangling) { + VectorFunctionShape VFS("_ZGVnN2vl_sin"); + + EXPECT_EQ(VFS.VF, (unsigned)2); + EXPECT_FALSE(VFS.IsMasked); + EXPECT_EQ(VFS.ISA, ISAKind::ISA_AdvancedSIMD); + + // Does call parseParamList() + EXPECT_TRUE(VFS.Parameters[0].isVector()); + EXPECT_EQ(VFS.Parameters[0].getParamPos(), (unsigned)0); + + EXPECT_EQ(VFS.Parameters[1].getLinearStepOrPos(), 1); + EXPECT_TRUE(VFS.Parameters[1].isLinear()); + EXPECT_EQ(VFS.Parameters[1].getParamPos(), (unsigned)1); + + EXPECT_EQ(VFS.ScalarName, "sin"); + EXPECT_EQ(VFS.VectorName, "_ZGVnN2vl_sin"); +} + +TEST(VectorFunctionABITests, FunctionalityTests) { + // Parse ISA Kind + EXPECT_EQ(VectorFunctionShape("_ZGVnN2vl_sin").ISA, + ISAKind::ISA_AdvancedSIMD); + EXPECT_EQ(VectorFunctionShape("_ZGVsN2v_sin").ISA, ISAKind::ISA_SVE); + EXPECT_EQ(VectorFunctionShape("_ZGVbN2v_sin").ISA, ISAKind::ISA_SSE); + EXPECT_EQ(VectorFunctionShape("_ZGVcN2v_sin").ISA, ISAKind::ISA_AVX); + EXPECT_EQ(VectorFunctionShape("_ZGVdN2_sin").ISA, ISAKind::ISA_AVX2); + EXPECT_EQ(VectorFunctionShape("_ZGVeN2_sin").ISA, ISAKind::ISA_AVX512); + EXPECT_DEATH(VectorFunctionShape("_ZGVzN2vl_sin"), "Invalid ISA Specified"); + + // Parse Mask Value + EXPECT_TRUE(VectorFunctionShape("_ZGVnM2v_sin").IsMasked); + EXPECT_FALSE(VectorFunctionShape("_ZGVnN2v_sin").IsMasked); + EXPECT_TRUE(VectorFunctionShape("_ZGVsN2v_sin").IsMasked); + EXPECT_TRUE(VectorFunctionShape("_ZGVsM2v_sin").IsMasked); + EXPECT_DEATH(VectorFunctionShape("_ZGVnO2v_sin"), "Invalid masking option"); + + // Parse Scalable Value + EXPECT_TRUE(VectorFunctionShape("_ZGVsMxv_sin").IsScalable); + EXPECT_FALSE(VectorFunctionShape("_ZGVsM2v_sin").IsScalable); + + // Parse VF + EXPECT_EQ(VectorFunctionShape("_ZGVnM2v_sin").VF, (unsigned)2); + EXPECT_EQ(VectorFunctionShape("_ZGVnM22v_sin").VF, (unsigned)22); + EXPECT_EQ(VectorFunctionShape("_ZGVsMxv_sin").VF, (unsigned)0); + EXPECT_DEATH(VectorFunctionShape("_ZGVnMxv_sin"), "Incompatible ISA"); + EXPECT_DEATH(VectorFunctionShape("_ZGVnN2Ts_sin"), + "Unexpected Parameter Kind"); + + // Parse Scalar Name + EXPECT_EQ(VectorFunctionShape("_ZGVnM2v_sin").ScalarName, "sin"); + EXPECT_EQ(VectorFunctionShape("_ZGVnM2v_sin(UserFunc)").ScalarName, "sin"); + EXPECT_EQ(VectorFunctionShape("_ZGVnM2v___sin_sin_sin").ScalarName, + "__sin_sin_sin"); + + // Get Vector Name + EXPECT_EQ(VectorFunctionShape::getVectorName("_ZGVnM2v_sin"), "_ZGVnM2v_sin"); + EXPECT_EQ(VectorFunctionShape::getVectorName("_ZGVnM2v_sin(UserFunc)"), + "UserFunc"); +}