--- /dev/null
+//===- 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");
+}
--- /dev/null
+//===------- 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");
+}