Index: llvm/include/llvm/Analysis/SearchVectorFunctionSystem.h =================================================================== --- /dev/null +++ llvm/include/llvm/Analysis/SearchVectorFunctionSystem.h @@ -0,0 +1,188 @@ +//===- 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 { + +/// 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 +struct VectorFunctionShape { + 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 + + // Equality checks + bool operator==(const VectorFunctionShape &other) const { + return (VF == other.VF && IsMasked == other.IsMasked && + IsScalable == other.IsScalable && ISA == other.ISA && + Parameters == other.Parameters); + } +}; + +// Vector Function ABI +namespace VFABI { +/// Checks ABI Signature +/// \param MangledName - Mangled name to be parsed +/// \param Result True if the MangledName follows the ABI signature +bool getABISignature(StringRef MangledName); +/// Gets Instruction Set Architecture +/// \param MangledName - Mangled name to be parsed +/// \param Result The ISA specified in the mangled name +ISAKind getISA(StringRef MangledName); +/// Checks for Mask (inbranch, notinbranch) +/// \param MangledName - Mangled name to be parsed +/// \param Result True if Masked +bool getIsMasked(StringRef MangledName); +/// Gets vectorization factor +/// \param MangledName - Mangled name to be parsed +/// \param Result Vectorization factor +unsigned getVF(StringRef MangledName); +/// Gets the name of the Scalar variant of the function +/// \param MangledName - Mangled name to be parsed +/// \param Result Scalar Function name +StringRef getScalarName(StringRef MangledName); +/// Gets the name of the Vector variant of the function +/// \param MangledName - Mangled name to be parsed +/// \param Result Vector Function name +StringRef getVectorName(StringRef MangledName); +/// Gets the ABI mangled name without redirection specified +/// \param MangledName - Mangled name to be parsed +/// \param Result Vector Function name +StringRef getPartMangledName(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, + SmallVector &Parameters); +/// Checks if it supports scalability +/// \param MangledName - Mangled name to be parsed +/// \param Result True if scalable version exists +bool getIsScalable(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,194 @@ +//===- 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; + +bool VFABI::getABISignature(StringRef MangledName) { + // Capture the ABI Signature value + return MangledName.startswith("_ZGV"); +} + +ISAKind VFABI::getISA(StringRef MangledName) { + // Capture the ISA value + StringRef ISAValue = MangledName.substr(4, 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"); + return ISA; +} + +bool VFABI::getIsMasked(StringRef MangledName) { + // Capture the MASK value + StringRef Mask; + Mask = MangledName.substr(5, 1); + if (VFABI::getISA(MangledName) == ISAKind::ISA_SVE) + return true; + assert((Mask.equals("N") || Mask.equals("M")) && "Invalid masking option"); + return Mask.equals("N") ? false : true; +} + +unsigned VFABI::getVF(StringRef MangledName) { + // Capture the VF + // VectorLength can be any positive integer + unsigned VF; + std::size_t Pos; + + Pos = MangledName.find_first_of("vlRLUu", 6); + if (!MangledName.substr(6, Pos - 6).compare("x")) { + assert(VFABI::getISA(MangledName) == ISAKind::ISA_SVE && + "Incompatible ISA"); + return 0; + } + MangledName.substr(6, Pos - 6).consumeInteger(10, VF); + return VF; +} + +bool VFABI::getIsScalable(StringRef MangledName) { + // Capture if it is Scalable or Not + bool IsSVE = VFABI::getISA(MangledName) == ISAKind::ISA_SVE; + bool IsVFZero = VFABI::getVF(MangledName) == 0; + return IsSVE && IsVFZero; +} + +StringRef VFABI::getScalarName(StringRef MangledName) { + // Get Scalar function name + StringRef ScalarFunctionName; + std::size_t Pos; + std::size_t NewPos; + + Pos = MangledName.find("_", 6) + 1; + NewPos = MangledName.find("(", Pos); + // Handles Case: custom vector function name not provided + if (NewPos == StringRef::npos) + NewPos = MangledName.str().length(); + ScalarFunctionName = MangledName.substr(Pos, NewPos - Pos); + + return ScalarFunctionName; +} + +StringRef VFABI::getVectorName(StringRef MangledName) { + // Get 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 VFABI::getPartMangledName(StringRef MangledName) { + StringRef PartMangledName; + std::size_t Pos; + + Pos = MangledName.find("("); + if (Pos == StringRef::npos) + PartMangledName = MangledName; + else + PartMangledName = MangledName.substr(0, Pos); + return PartMangledName; +} + +void VFABI::parseParamList(StringRef ParamList, + SmallVector &Params) { + 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 newRecord.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); + ParamKind = ParamType::convertToParameterKind(ParamKindStr); + Params.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); + } + Params.push_back(Parameter); + } + ParamPos++; + Pos = NewPos; + } + + // Last param value || only param + // 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.str().length()) > Pos + 1) { + StringRef StrLinearStepOrPos = + ParamList.substr(Pos + 1, (ParamList.str().length()) - (Pos + 1)); + StrLinearStepOrPos.consumeInteger(10, LinearStepOrPos); + Params.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); + } + Params.push_back(Parameter); + } +} \ No newline at end of file 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 + SearchVectorFunctionSystemTest.cpp SparsePropagation.cpp TargetLibraryInfoTest.cpp TBAATest.cpp Index: llvm/unittests/Analysis/SearchVectorFunctionSystemTest.cpp =================================================================== --- /dev/null +++ llvm/unittests/Analysis/SearchVectorFunctionSystemTest.cpp @@ -0,0 +1,82 @@ +//===------- SearchVectorFunctionSystemTest.cpp - SVFS 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; + +TEST(VectorFunctionABITests, ParamListParsing) { + SmallVector Output; + + VFABI::parseParamList("vl16Ls32R3l", Output); + + EXPECT_EQ(Output[0].getParamPos(), (unsigned)0); + EXPECT_TRUE(Output[0].isVector()); + + EXPECT_EQ(Output[1].getParamPos(), (unsigned)1); + EXPECT_TRUE(Output[1].isLinear()); + EXPECT_EQ(Output[1].getLinearStepOrPos(), 16); + + EXPECT_EQ(Output[2].getParamPos(), (unsigned)2); + EXPECT_TRUE(Output[2].isLinearValPos()); + EXPECT_EQ(Output[2].getLinearStepOrPos(), 32); + + EXPECT_EQ(Output[3].getParamPos(), (unsigned)3); + EXPECT_TRUE(Output[3].isLinearRef()); + EXPECT_EQ(Output[3].getLinearStepOrPos(), 3); + + EXPECT_EQ(Output[4].getParamPos(), (unsigned)4); + EXPECT_TRUE(Output[4].isLinear()); + EXPECT_EQ(Output[4].getLinearStepOrPos(), 1); + + EXPECT_DEATH(VFABI::parseParamList("Ts", Output), + "Unexpected Parameter Kind"); + + EXPECT_DEATH(VFABI::parseParamList("vLs", Output), + "Step Not Specified for given ParameterKind"); +} + +TEST(VectorFunctionABITests, FunctionalityTests) { + // Getting ISA Kind + EXPECT_EQ(VFABI::getISA("_ZGVnN2_sin"), ISAKind::ISA_AdvancedSIMD); + EXPECT_EQ(VFABI::getISA("_ZGVsN2_sin"), ISAKind::ISA_SVE); + EXPECT_EQ(VFABI::getISA("_ZGVbN2_sin"), ISAKind::ISA_SSE); + EXPECT_EQ(VFABI::getISA("_ZGVcN2_sin"), ISAKind::ISA_AVX); + EXPECT_EQ(VFABI::getISA("_ZGVdN2_sin"), ISAKind::ISA_AVX2); + EXPECT_EQ(VFABI::getISA("_ZGVeN2_sin"), ISAKind::ISA_AVX512); + EXPECT_DEATH(VFABI::getISA("_ZGVzN2_sin"), "Invalid ISA Specified"); + + // Getting Mask Value + EXPECT_TRUE(VFABI::getIsMasked("_ZGVnM2v_sin")); + EXPECT_FALSE(VFABI::getIsMasked("_ZGVnN2v_sin")); + EXPECT_TRUE(VFABI::getIsMasked("_ZGVsN2v_sin")); + EXPECT_TRUE(VFABI::getIsMasked("_ZGVsM2v_sin")); + EXPECT_DEATH(VFABI::getIsMasked("_ZGVnO2v_sin"), "Invalid masking option"); + + // Getting Scalable Value + EXPECT_TRUE(VFABI::getIsScalable("_ZGVsMxv_sin")); + EXPECT_FALSE(VFABI::getIsScalable("_ZGVsM2v_sin")); + + // Getting VF + EXPECT_EQ(VFABI::getVF("_ZGVnM2v_sin"), (unsigned)2); + EXPECT_EQ(VFABI::getVF("_ZGVnM22v_sin"), (unsigned)22); + EXPECT_EQ(VFABI::getVF("_ZGVsMxv_sin"), (unsigned)0); + EXPECT_DEATH(VFABI::getVF("_ZGVnMxv_sin"), "Incompatible ISA"); + + // Getting Scalar Name + EXPECT_EQ(VFABI::getScalarName("_ZGVnM2v_sin"), "sin"); + EXPECT_EQ(VFABI::getScalarName("_ZGVnM2v_sin(UserFunc)"), "sin"); + EXPECT_EQ(VFABI::getScalarName("_ZGVnM2v___sin_sin_sin"), "__sin_sin_sin"); + + // Getting Vector Name + EXPECT_EQ(VFABI::getVectorName("_ZGVnM2v_sin"), "_ZGVnM2v_sin"); + EXPECT_EQ(VFABI::getVectorName("_ZGVnM2v_sin(UserFunc)"), "UserFunc"); +}