Index: llvm/include/llvm/Analysis/SearchVectorFunctionSystem.h =================================================================== --- /dev/null +++ llvm/include/llvm/Analysis/SearchVectorFunctionSystem.h @@ -0,0 +1,140 @@ +//===- 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 +// +//===----------------------------------------------------------------------===// +// +/// This file contains objects and utilities that are needed to handle +/// vector functions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_SVFS_H +#define LLVM_ANALYSIS_SVFS_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" + +namespace llvm { + +/// Describes the type of Parameters +enum class VFParamKind { + 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 VFISAKind { + ISA_AdvancedSIMD, + ISA_SVE, + ISA_SSE, + ISA_AVX, + ISA_AVX2, + ISA_AVX512, + ISA_Invalid +}; + +/// Encapsulates information needed to describe a parameter. +struct VFParameter { + unsigned ParamPos; // Parameter Position in Scalar Function. + VFParamKind ParamKind; // Kind of Parameter. + int LinearStepOrPos; // Step or Position of the Parameter. + unsigned Alignment = 1; // Optional aligment, in bytes, defaulted to 1. + VFParameter() {} + VFParameter(unsigned ParamPos, VFParamKind ParamKind, int LinearStepOrPos) + : ParamPos(ParamPos), ParamKind(ParamKind), + LinearStepOrPos(LinearStepOrPos) {} + + bool operator==(const VFParameter &other) const { + return (ParamPos == other.ParamPos && ParamKind == other.ParamKind && + LinearStepOrPos == other.LinearStepOrPos); + } + + static VFParamKind convertToVFParamKind(StringRef kind) { + VFParamKind ParamKind = StringSwitch(kind) + .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::Invalid); + + if (ParamKind == VFParamKind::Invalid) + llvm_unreachable("Unexpected Parameter Kind"); + return ParamKind; + } + + unsigned getParamPos() { return ParamPos; } + + void setParamPos(unsigned Position) { ParamPos = Position; } +}; + +namespace VFABI { +// Parse a string in the format +// _ZGV_[()]. +// +// \parame MangledName -> input string. +// \param VF -> holds if is a number. +// \param IsMasked -> true if == "M", false if == "N". +// \param IsScalable -> true if == "x". +// \param ISA -> maps to . +// \param Parameters -> holds the . +// \param ScalarName -> holds the . +// \param VectorVarian -> holds is present, otherwise holds +// _ZGV_. +bool tryParserVFABIName(const StringRef mangledName, unsigned &VF, + bool &IsMasked, bool &IsScalable, VFISAKind &ISA, + SmallVector &Parameters, + StringRef &ScalarName, StringRef &VectorVariant); + +} // end namespace VFABI + +/// Contains the information about the kind of vectoriazation available. +class VFShape { +public: + VFShape() {} + unsigned VF; // Vectorization factor + bool IsMasked; // True if Masked + bool IsScalable; // True if Scalable + VFISAKind 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 VFShape &other) const { + return (VF == other.VF && IsMasked == other.IsMasked && + IsScalable == other.IsScalable && ISA == other.ISA && + Parameters == other.Parameters); + } + + static VFShape getFromVFABI(StringRef MangledName) { + VFShape VFS; + if (VFABI::tryParserVFABIName(MangledName, VFS.VF, VFS.IsMasked, + VFS.IsScalable, VFS.ISA, VFS.Parameters, + VFS.ScalarName, VFS.VectorName)) + return VFS; + + assert(0 && "Invalid vector function ABI name."); + } +}; + +} // end namespace llvm + +#endif // LLVM_ANALYSIS_SVFS_H 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,266 @@ +//===- 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" + +using namespace llvm; + +namespace { +/// Utilities for the Vector Function ABI name parser. +/// +/// `get*` methods: extract values from fixed parts of the string, +/// without modifying it. +/// +/// `consume*` methods: find variable size tokens that are +/// mandatory. The string to be parsed is advanced. +/// +/// `tryParse` methods: find optional tokens and advance the string +/// to be parsed. + +bool getISA(const StringRef MangledName, VFISAKind &ISA) { + // Capture the ISA value (one char): `_ZGV...`. + StringRef ISAValue = MangledName.substr(4, 1); + + ISA = StringSwitch(ISAValue) + .Case("n", VFISAKind::ISA_AdvancedSIMD) + .Case("s", VFISAKind::ISA_SVE) + .Case("b", VFISAKind::ISA_SSE) + .Case("c", VFISAKind::ISA_AVX) + .Case("d", VFISAKind::ISA_AVX2) + .Case("e", VFISAKind::ISA_AVX512) + .Default(VFISAKind::ISA_Invalid); + + return ISA != VFISAKind::ISA_Invalid; +} + +bool getMask(const StringRef MangledName, bool &IsMasked) { + // Capture the MASK value (one char): `_ZGV...`. + StringRef Mask = MangledName.substr(5, 1); + + if (Mask == "M") { + IsMasked = true; + return true; + } + + if (Mask == "N") { + IsMasked = false; + return true; + } + + return false; +} + +bool consumeVLEN(StringRef &ParseString, unsigned &VF, bool &IsScalable) { + if (ParseString.consume_front("x")) { + VF = 0; + IsScalable = true; + return true; + } + + if (ParseString.consumeInteger(10, VF)) + return false; + + IsScalable = false; + return true; +} + +// Return types for the parser functions. +enum class ParseRet { + OK, // Found. + None, // Not found. + Error // Syntax error. +}; + +ParseRet tryParseLinearTokenWithRuntimeStep(StringRef &ParseString, + VFParamKind &PKind, int &StepOrPos, + const StringRef Token) { + assert((Token == "ls" || Token == "Rs" || Token == "Us" || Token == "Ls") && + "Not a valid token."); + if (ParseString.consume_front(Token)) { + PKind = VFParameter::convertToVFParamKind(Token); + if (ParseString.consumeInteger(10, StepOrPos)) + return ParseRet::Error; + return ParseRet::OK; + } + return ParseRet::None; +} + +ParseRet tryParseLinearWithRuntimeStep(StringRef &ParseString, + VFParamKind &PKind, int &StepOrPos) { + ParseRet Ret; + + // "ls" + Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "ls"); + if (Ret != ParseRet::None) + return Ret; + + // "Rs" + Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Rs"); + if (Ret != ParseRet::None) + return Ret; + + // "Ls" + Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Ls"); + if (Ret != ParseRet::None) + return Ret; + + // "Us" + Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Us"); + if (Ret != ParseRet::None) + return Ret; + + return ParseRet::None; +} + +bool consumeCompileTimeLinearToken(StringRef &ParseString, VFParamKind &PKind, + int &StepOrPos, const StringRef Token) { + assert((Token == "l" || Token == "R" || Token == "U" || Token == "L") && + "Not a valid token."); + if (ParseString.consume_front(Token)) { + PKind = VFParameter::convertToVFParamKind(Token); + const bool Negate = ParseString.consume_front("n"); + if (ParseString.consumeInteger(10, StepOrPos)) + StepOrPos = 1; + if (Negate) + StepOrPos *= -1; + return true; + } + + return false; +} + +ParseRet tryParseLinearWithCompileTimeStep(StringRef &ParseString, + VFParamKind &PKind, int &StepOrPos) { + // "l" + if (consumeCompileTimeLinearToken(ParseString, PKind, StepOrPos, "l")) + return ParseRet::OK; + + // "R" + if (consumeCompileTimeLinearToken(ParseString, PKind, StepOrPos, "R")) + return ParseRet::OK; + + // "L" + if (consumeCompileTimeLinearToken(ParseString, PKind, StepOrPos, "L")) + return ParseRet::OK; + + // "U" + if (consumeCompileTimeLinearToken(ParseString, PKind, StepOrPos, "U")) + return ParseRet::OK; + + return ParseRet::None; +} + +ParseRet tryParseParameter(StringRef &ParseString, VFParamKind &PKind, + int &StepOrPos) { + if (ParseString.consume_front("v")) { + PKind = VFParamKind::Vector; + StepOrPos = 0; + return ParseRet::OK; + } + + ParseRet HasLinear = + tryParseLinearWithRuntimeStep(ParseString, PKind, StepOrPos); + if (HasLinear != ParseRet::None) + return HasLinear; + + HasLinear = tryParseLinearWithCompileTimeStep(ParseString, PKind, StepOrPos); + if (HasLinear != ParseRet::None) + return HasLinear; + + return ParseRet::None; +} + +ParseRet tryParseAlign(StringRef &ParseString, unsigned &Align) { + // "a" + if (ParseString.consume_front("a")) { + if (ParseString.consumeInteger(10, Align)) + return ParseRet::Error; + return ParseRet::OK; + } + + return ParseRet::None; +} +} // namespace + +// Format of the ABI name: +// _ZGV_[()] +bool VFABI::tryParserVFABIName(const StringRef MangledName, unsigned &VF, + bool &IsMasked, bool &IsScalable, VFISAKind &ISA, + SmallVector &Parameters, + StringRef &ScalarName, + StringRef &VectorVariant) { + // Assume there is no custom name , and therefore the + // vector name consists of + // _ZGV_. + VectorVariant = MangledName; + + // Parse the fixed size part of the manled name + if (!MangledName.startswith("_ZGV")) + return false; + + if (!getISA(MangledName, ISA)) + return false; + + if (!getMask(MangledName, IsMasked)) + return false; + + // First, drop the first 6 chars of the mangled name: _ZGV + StringRef ParseString = MangledName.drop_front(6); + + // Parse the variable size, starting from . + if (!consumeVLEN(ParseString, VF, IsScalable)) + return false; + + // Parse the . + ParseRet ParamFound; + do { + const unsigned ParameterPos = Parameters.size(); + VFParamKind PKind; + int StepOrPos; + ParamFound = tryParseParameter(ParseString, PKind, StepOrPos); + + // Bail off if there is a parsing error in the parsing of the parameter. + if (ParamFound == ParseRet::Error) + return false; + + if (ParamFound == ParseRet::OK) { + VFParameter Parameter(ParameterPos, PKind, StepOrPos); + + // Look for the alignment token "a ". + ParseRet AlignFound = tryParseAlign(ParseString, Parameter.Alignment); + // Bail off if there is a syntax error in the align token. + if (AlignFound == ParseRet::Error) + return false; + + // Add the parameter. + Parameters.push_back(Parameter); + } + } while (ParamFound == ParseRet::OK); + + // Check for the and the optional , which + // are separated from the prefix with "_" + if (!ParseString.consume_front("_")) + return false; + + // The rest of the string must be in the format: + // [()] + ScalarName = + ParseString.take_while([](char In) -> bool { return In != '('; }); + + // Reduce ParseString to [()]. + ParseString = ParseString.ltrim(ScalarName); + // Find the optional custom name redirection. + if (ParseString.consume_front("(")) { + if (!ParseString.consume_back(")")) + return false; + // Update the vector variant with the one specified by the user. + VectorVariant = ParseString; + } + + return true; +} Index: llvm/tools/vfabi-demangle-fuzzer/CMakeLists.txt =================================================================== --- /dev/null +++ llvm/tools/vfabi-demangle-fuzzer/CMakeLists.txt @@ -0,0 +1,7 @@ +set(LLVM_LINK_COMPONENTS + Analysis + Support +) +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,36 @@ +//===-- 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); + unsigned VF; + bool IsMasked; + VFISAKind ISA; + SmallVector Parameters; + StringRef ScalarName; + StringRef VectorVariant; + bool IsScalable; + bool Ret = + VFABI::tryParserVFABIName(MangledName, VF, IsMasked, IsScalable, ISA, + Parameters, ScalarName, VectorVariant); + + // 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"(Ret) : "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,212 @@ +//===------- 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 "gtest/gtest.h" + +using namespace llvm; + +TEST(VectorFunctionABITests, ParamListParsing) { + // Testing "vl16Ls32R3l" + VFShape VFS = VFShape::getFromVFABI("_ZGVnN2vl16Ls32R3l_foo"); + EXPECT_EQ(VFS.Parameters.size(), (unsigned)5); + EXPECT_EQ(VFS.Parameters[0], VFParameter({0, VFParamKind::Vector, 0})); + EXPECT_EQ(VFS.Parameters[1], VFParameter({1, VFParamKind::OMP_Linear, 16})); + EXPECT_EQ(VFS.Parameters[2], + VFParameter({2, VFParamKind::OMP_LinearValPos, 32})); + EXPECT_EQ(VFS.Parameters[3], VFParameter({3, VFParamKind::OMP_LinearRef, 3})); + EXPECT_EQ(VFS.Parameters[4], VFParameter({4, VFParamKind::OMP_Linear, 1})); +} + +TEST(VectorFunctionABITests, ParseScalarName) { + // Parse Scalar Name + EXPECT_EQ(VFShape::getFromVFABI("_ZGVnM2v_sin").ScalarName, "sin"); + EXPECT_EQ(VFShape::getFromVFABI("_ZGVnM2v_sin(UserFunc)").ScalarName, "sin"); + EXPECT_EQ(VFShape::getFromVFABI("_ZGVnM2v___sin_sin_sin").ScalarName, + "__sin_sin_sin"); +} + +TEST(VectorFunctionABITests, ParseVectorName) { + // Get Vector Name + EXPECT_EQ(VFShape::getFromVFABI("_ZGVnM2v_sin").VectorName, "_ZGVnM2v_sin"); + EXPECT_EQ(VFShape::getFromVFABI("_ZGVnM2v_sin(UserFunc)").VectorName, + "UserFunc"); +} + +namespace { +// Test fixture needed that holds the veariables needed by the parser. +class VFABIParserTest : public ::testing::Test { +protected: + unsigned VF; + bool IsMasked; + VFISAKind ISA; + SmallVector Parameters; + StringRef ScalarName; + StringRef VectorVariant; + bool IsScalable; + // Reset the parser output. + void reset() { + VF = 0; + IsMasked = false; + ISA = VFISAKind::ISA_Invalid; + Parameters.clear(); + ScalarName = ""; + VectorVariant = ""; + IsScalable = false; + } + // Invoke the parser. + bool invokeParser(const StringRef MangledName) { + reset(); + return VFABI::tryParserVFABIName(MangledName, VF, IsMasked, IsScalable, ISA, + Parameters, ScalarName, VectorVariant); + } +}; +} // unnamed namespace + +TEST_F(VFABIParserTest, Parse) { + EXPECT_TRUE(invokeParser("_ZGVnN2vls2Ls27Us4Rs5l1L10U100R1000_sin")); + EXPECT_EQ(VF, (unsigned)2); + EXPECT_FALSE(IsMasked); + EXPECT_EQ(ISA, VFISAKind::ISA_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(VectorVariant, "_ZGVnN2vls2Ls27Us4Rs5l1L10U100R1000_sin"); +} + +TEST_F(VFABIParserTest, ParseVectorVariant) { + EXPECT_TRUE(invokeParser("_ZGVnN2v_sin(my_v_sin)")); + EXPECT_EQ(VF, (unsigned)2); + EXPECT_FALSE(IsMasked); + EXPECT_FALSE(IsScalable); + EXPECT_EQ(ISA, VFISAKind::ISA_AdvancedSIMD); + EXPECT_EQ(Parameters.size(), (unsigned)1); + EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector, 0})); + EXPECT_EQ(ScalarName, "sin"); + EXPECT_EQ(VectorVariant, "my_v_sin"); +} + +TEST_F(VFABIParserTest, LinearWithCompileTimeNegativeStep) { + EXPECT_TRUE(invokeParser("_ZGVnN2ln1Ln10Un100Rn1000_sin")); + EXPECT_EQ(VF, (unsigned)2); + EXPECT_FALSE(IsMasked); + EXPECT_EQ(ISA, VFISAKind::ISA_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(VectorVariant, "_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::ISA_SVE); + EXPECT_EQ(ScalarName, "sin"); + EXPECT_EQ(VectorVariant, "_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::ISA_SVE); + EXPECT_EQ(ScalarName, "sin"); + EXPECT_EQ(VectorVariant, "_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, ValidAndInvalidISA) { + EXPECT_FALSE(invokeParser("_ZGVqN2v_sin")); + + EXPECT_TRUE(invokeParser("_ZGVnN2v_sin")); + EXPECT_EQ(ISA, VFISAKind::ISA_AdvancedSIMD); + + EXPECT_TRUE(invokeParser("_ZGVsN2v_sin")); + EXPECT_EQ(ISA, VFISAKind::ISA_SVE); + + EXPECT_TRUE(invokeParser("_ZGVbN2v_sin")); + EXPECT_EQ(ISA, VFISAKind::ISA_SSE); + + EXPECT_TRUE(invokeParser("_ZGVcN2v_sin")); + EXPECT_EQ(ISA, VFISAKind::ISA_AVX); + + EXPECT_TRUE(invokeParser("_ZGVdN2v_sin")); + EXPECT_EQ(ISA, VFISAKind::ISA_AVX2); + + EXPECT_TRUE(invokeParser("_ZGVeN2v_sin")); + EXPECT_EQ(ISA, VFISAKind::ISA_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("_ZGVsM2l2a2_sin")); + EXPECT_EQ(Parameters.size(), (unsigned)1); + EXPECT_EQ(Parameters[0].Alignment, (unsigned)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")); +}