1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-18 10:32:48 +02:00

[llvm][VectorUtils] Tweak VFShape for scalable vector functions.

Summary:
This patch makes sure that the field VFShape.VF is greater than zero
when demangling the vector function name of scalable vector functions
encoded in the "vector-function-abi-variant" attribute.

This change is required to be able to provide instances of VFShape
that can be used to query the VFDatabase for the vectorization passes,
as such passes always require a positive value for the Vectorization Factor (VF)
needed by the vectorization process.

It is not possible to extract the value of VFShape.VF from the mangled
name of scalable vector functions, because it is encoded as
`x`. Therefore, the VFABI demangling function has been modified to
extract such information from the IR declaration of the vector
function, under the assumption that _all_ vectors in the signature of
the vector function have the same number of lanes. Such assumption is
valid because it is also assumed by the Vector Function ABI
specifications supported by the demangling function (x86, AArch64, and
LLVM internal one).

The unit tests that demangle scalable names have been modified by
adding the IR module that carries the declaration of the vector
function name being demangled.

In particular, the demangling function fails in the following cases:

1. When the declaration of the scalable vector function is not
    present in the module.

2. When the value of VFSHape.VF is not greater than 0.

Reviewers: jdoerfert, sdesmalen, andwar

Reviewed By: jdoerfert

Subscribers: mgorny, kristof.beyls, hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D73286
This commit is contained in:
Francesco Petrogalli 2020-01-22 22:34:27 +00:00
parent fdec1f2e2e
commit 308e2db83d
7 changed files with 249 additions and 88 deletions

View File

@ -161,7 +161,12 @@ static constexpr char const *_LLVM_Scalarize_ = "_LLVM_Scalarize_";
/// ///
/// \param MangledName -> input string in the format /// \param MangledName -> input string in the format
/// _ZGV<isa><mask><vlen><parameters>_<scalarname>[(<redirection>)]. /// _ZGV<isa><mask><vlen><parameters>_<scalarname>[(<redirection>)].
Optional<VFInfo> tryDemangleForVFABI(StringRef MangledName); /// \param M -> Module used to retrive informations about the vector
/// function that are not possible to retrieve from the mangled
/// name. At the moment, this parameter is needed only to retrive the
/// Vectorization Factor of scalable vector functions from their
/// respective IR declarations.
Optional<VFInfo> tryDemangleForVFABI(StringRef MangledName, const Module &M);
/// Retrieve the `VFParamKind` from a string token. /// Retrieve the `VFParamKind` from a string token.
VFParamKind getVFParamKindFromString(const StringRef Token); VFParamKind getVFParamKindFromString(const StringRef Token);
@ -200,7 +205,8 @@ class VFDatabase {
SmallVector<std::string, 8> ListOfStrings; SmallVector<std::string, 8> ListOfStrings;
VFABI::getVectorVariantNames(CI, ListOfStrings); VFABI::getVectorVariantNames(CI, ListOfStrings);
for (const auto &MangledName : ListOfStrings) { for (const auto &MangledName : ListOfStrings) {
const Optional<VFInfo> Shape = VFABI::tryDemangleForVFABI(MangledName); const Optional<VFInfo> Shape =
VFABI::tryDemangleForVFABI(MangledName, *(CI.getModule()));
// A match is found via scalar and vector names, and also by // A match is found via scalar and vector names, and also by
// ensuring that the variant described in the attribute has a // ensuring that the variant described in the attribute has a
// corresponding definition or declaration of the vector // corresponding definition or declaration of the vector

View File

@ -70,6 +70,9 @@ ParseRet tryParseMask(StringRef &MangledName, bool &IsMasked) {
/// ///
ParseRet tryParseVLEN(StringRef &ParseString, unsigned &VF, bool &IsScalable) { ParseRet tryParseVLEN(StringRef &ParseString, unsigned &VF, bool &IsScalable) {
if (ParseString.consume_front("x")) { if (ParseString.consume_front("x")) {
// Set VF to 0, to be later adjusted to a value grater than zero
// by looking at the signature of the vector function with
// `getECFromSignature`.
VF = 0; VF = 0;
IsScalable = true; IsScalable = true;
return ParseRet::OK; return ParseRet::OK;
@ -78,6 +81,10 @@ ParseRet tryParseVLEN(StringRef &ParseString, unsigned &VF, bool &IsScalable) {
if (ParseString.consumeInteger(10, VF)) if (ParseString.consumeInteger(10, VF))
return ParseRet::Error; return ParseRet::Error;
// The token `0` is invalid for VLEN.
if (VF == 0)
return ParseRet::Error;
IsScalable = false; IsScalable = false;
return ParseRet::OK; return ParseRet::OK;
} }
@ -287,11 +294,50 @@ ParseRet tryParseAlign(StringRef &ParseString, Align &Alignment) {
return ParseRet::None; return ParseRet::None;
} }
#ifndef NDEBUG
// Verify the assumtion that all vectors in the signature of a vector
// function have the same number of elements.
bool verifyAllVectorsHaveSameWidth(FunctionType *Signature) {
SmallVector<VectorType *, 2> VecTys;
if (auto *RetTy = dyn_cast<VectorType>(Signature->getReturnType()))
VecTys.push_back(RetTy);
for (auto *Ty : Signature->params())
if (auto *VTy = dyn_cast<VectorType>(Ty))
VecTys.push_back(VTy);
if (VecTys.size() <= 1)
return true;
assert(VecTys.size() > 1 && "Invalid number of elements.");
const ElementCount EC = VecTys[0]->getElementCount();
return llvm::all_of(
llvm::make_range(VecTys.begin() + 1, VecTys.end()),
[&EC](VectorType *VTy) { return (EC == VTy->getElementCount()); });
}
#endif // NDEBUG
// Extract the VectorizationFactor from a given function signature,
// under the assumtion that all vectors have the same number of
// elements, i.e. same ElementCount.Min.
ElementCount getECFromSignature(FunctionType *Signature) {
assert(verifyAllVectorsHaveSameWidth(Signature) &&
"Invalid vector signature.");
if (auto *RetTy = dyn_cast<VectorType>(Signature->getReturnType()))
return RetTy->getElementCount();
for (auto *Ty : Signature->params())
if (auto *VTy = dyn_cast<VectorType>(Ty))
return VTy->getElementCount();
return ElementCount(/*Min=*/1, /*Scalable=*/false);
}
} // namespace } // namespace
// Format of the ABI name: // Format of the ABI name:
// _ZGV<isa><mask><vlen><parameters>_<scalarname>[(<redirection>)] // _ZGV<isa><mask><vlen><parameters>_<scalarname>[(<redirection>)]
Optional<VFInfo> VFABI::tryDemangleForVFABI(StringRef MangledName) { Optional<VFInfo> VFABI::tryDemangleForVFABI(StringRef MangledName,
const Module &M) {
const StringRef OriginalName = MangledName; const StringRef OriginalName = MangledName;
// Assume there is no custom name <redirection>, and therefore the // Assume there is no custom name <redirection>, and therefore the
// vector name consists of // vector name consists of
@ -402,6 +448,32 @@ Optional<VFInfo> VFABI::tryDemangleForVFABI(StringRef MangledName) {
assert(Parameters.back().ParamKind == VFParamKind::GlobalPredicate && assert(Parameters.back().ParamKind == VFParamKind::GlobalPredicate &&
"The global predicate must be the last parameter"); "The global predicate must be the last parameter");
// Adjust the VF for scalable signatures. The EC.Min is not encoded
// in the name of the function, but it is encoded in the IR
// signature of the function. We need to extract this information
// because it is needed by the loop vectorizer, which reasons in
// terms of VectorizationFactor or ElementCount. In particular, we
// need to make sure that the VF field of the VFShape class is never
// set to 0.
if (IsScalable) {
const Function *F = M.getFunction(VectorName);
// The declaration of the function must be present in the module
// to be able to retrieve its signature.
if (!F)
return None;
const ElementCount EC = getECFromSignature(F->getFunctionType());
VF = EC.Min;
}
// Sanity checks.
// 1. We don't accept a zero lanes vectorization factor.
// 2. We don't accept the demangling if the vector function is not
// present in the module.
if (VF == 0)
return None;
if (!M.getFunction(VectorName))
return None;
const VFShape Shape({VF, IsScalable, Parameters}); const VFShape Shape({VF, IsScalable, Parameters});
return VFInfo({Shape, std::string(ScalarName), std::string(VectorName), ISA}); return VFInfo({Shape, std::string(ScalarName), std::string(VectorName), ISA});
} }

View File

@ -1175,7 +1175,7 @@ void VFABI::getVectorVariantNames(
for (auto &S : SetVector<StringRef>(ListAttr.begin(), ListAttr.end())) { for (auto &S : SetVector<StringRef>(ListAttr.begin(), ListAttr.end())) {
#ifndef NDEBUG #ifndef NDEBUG
LLVM_DEBUG(dbgs() << "VFABI: adding mapping '" << S << "'\n"); LLVM_DEBUG(dbgs() << "VFABI: adding mapping '" << S << "'\n");
Optional<VFInfo> Info = VFABI::tryDemangleForVFABI(S); Optional<VFInfo> Info = VFABI::tryDemangleForVFABI(S, *(CI.getModule()));
assert(Info.hasValue() && "Invalid name for a VFABI variant."); assert(Info.hasValue() && "Invalid name for a VFABI variant.");
assert(CI.getModule()->getFunction(Info.getValue().VectorName) && assert(CI.getModule()->getFunction(Info.getValue().VectorName) &&
"Vector function is missing."); "Vector function is missing.");

View File

@ -301,7 +301,7 @@ void VFABI::setVectorVariantNames(
#ifndef NDEBUG #ifndef NDEBUG
for (const std::string &VariantMapping : VariantMappings) { for (const std::string &VariantMapping : VariantMappings) {
LLVM_DEBUG(dbgs() << "VFABI: adding mapping '" << VariantMapping << "'\n"); LLVM_DEBUG(dbgs() << "VFABI: adding mapping '" << VariantMapping << "'\n");
Optional<VFInfo> VI = VFABI::tryDemangleForVFABI(VariantMapping); Optional<VFInfo> VI = VFABI::tryDemangleForVFABI(VariantMapping, *M);
assert(VI.hasValue() && "Cannot add an invalid VFABI name."); assert(VI.hasValue() && "Cannot add an invalid VFABI name.");
assert(M->getNamedValue(VI.getValue().VectorName) && assert(M->getNamedValue(VI.getValue().VectorName) &&
"Cannot add variant to attribute: " "Cannot add variant to attribute: "

View File

@ -1,5 +1,7 @@
set(LLVM_LINK_COMPONENTS set(LLVM_LINK_COMPONENTS
Analysis Analysis
AsmParser
Core
Support Support
) )
add_llvm_fuzzer(vfabi-demangler-fuzzer add_llvm_fuzzer(vfabi-demangler-fuzzer

View File

@ -11,12 +11,27 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "llvm/Analysis/VectorUtils.h" #include "llvm/Analysis/VectorUtils.h"
#include "llvm/AsmParser/Parser.h"
using namespace llvm; using namespace llvm;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
LLVMContext Ctx;
SMDiagnostic Err;
const std::unique_ptr<Module> M =
parseAssemblyString("declare i32 @foo(i32 )\n", Err, Ctx);
const StringRef MangledName((const char *)Data, Size); const StringRef MangledName((const char *)Data, Size);
const auto Info = VFABI::tryDemangleForVFABI(MangledName); // Make sure that whatever symbol the demangler is operating on is
// present in the module (the signature is not important). This is
// because `tryDemangleForVFABI` fails if the function is not
// present. We need to make sure we can even invoke
// `getOrInsertFunction` because such method asserts on strings with
// zeroes.
if (!MangledName.empty() && MangledName.find_first_of(0) == StringRef::npos)
M->getOrInsertFunction(
MangledName,
FunctionType::get(Type::getVoidTy(M->getContext()), false));
const auto Info = VFABI::tryDemangleForVFABI(MangledName, *M);
// Do not optimize away the return value. Inspired by // Do not optimize away the return value. Inspired by
// https://github.com/google/benchmark/blob/master/include/benchmark/benchmark.h#L307-L345 // https://github.com/google/benchmark/blob/master/include/benchmark/benchmark.h#L307-L345

View File

@ -13,79 +13,34 @@
using namespace llvm; using namespace llvm;
// This test makes sure that the demangling 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 { namespace {
// Test fixture needed that holds the veariables needed by the parser. // Test fixture needed that holds the veariables needed by the parser.
class VFABIParserTest : public ::testing::Test { class VFABIParserTest : public ::testing::Test {
private: private:
// Parser output. // Parser output.
VFInfo Info; VFInfo Info;
// Reset the parser output references. // Reset the data needed for the test.
void reset() { Info = VFInfo(); } void reset(const StringRef Name, const StringRef IRType) {
M = parseAssemblyString("declare void @dummy()", Err, Ctx);
EXPECT_NE(M.get(), nullptr) << "Loading an invalid module.\n "
<< Err.getMessage() << "\n";
Type *Ty = parseType(IRType, Err, *(M.get()));
FunctionType *FTy = dyn_cast<FunctionType>(Ty);
EXPECT_NE(FTy, nullptr) << "Invalid function type string: " << IRType
<< "\n"
<< Err.getMessage() << "\n";
FunctionCallee F = M->getOrInsertFunction(Name, FTy);
EXPECT_NE(F.getCallee(), nullptr)
<< "The function must be present in the module\n";
// Reset the VFInfo
Info = VFInfo();
}
// Data needed to load the optional IR passed to invokeParser
LLVMContext Ctx;
SMDiagnostic Err;
std::unique_ptr<Module> M;
// CallInst *CI;
protected: protected:
// Referencies to the parser output field. // Referencies to the parser output field.
unsigned &VF = Info.Shape.VF; unsigned &VF = Info.Shape.VF;
@ -94,10 +49,33 @@ protected:
std::string &ScalarName = Info.ScalarName; std::string &ScalarName = Info.ScalarName;
std::string &VectorName = Info.VectorName; std::string &VectorName = Info.VectorName;
bool &IsScalable = Info.Shape.IsScalable; bool &IsScalable = Info.Shape.IsScalable;
// Invoke the parser. // Invoke the parser. We need to make sure that a function exist in
bool invokeParser(const StringRef MangledName) { // the module because the parser fails if such function don't
reset(); // exists. Every time this method is invoked the state of the test
const auto OptInfo = VFABI::tryDemangleForVFABI(MangledName); // is reset.
//
// \p MangledName -> the string the parser has to demangle.
//
// \p VectorName -> optional vector name that the method needs to
// use to create the function in the module if it differs from the
// standard mangled name.
//
// \p IRType -> FunctionType string to be used for the signature of
// the vector function. The correct signature is needed by the
// parser only for scalable functions. For the sake of testing, the
// generic fixed-length case can use as signature `void()`.
//
bool invokeParser(const StringRef MangledName,
const StringRef VectorName = "",
const StringRef IRType = "void()") {
StringRef Name = MangledName;
if (!VectorName.empty())
Name = VectorName;
// Reset the VFInfo and the Module to be able to invoke
// `invokeParser` multiple times in the same test.
reset(Name, IRType);
const auto OptInfo = VFABI::tryDemangleForVFABI(MangledName, *(M.get()));
if (OptInfo.hasValue()) { if (OptInfo.hasValue()) {
Info = OptInfo.getValue(); Info = OptInfo.getValue();
return true; return true;
@ -120,6 +98,67 @@ protected:
}; };
} // unnamed namespace } // unnamed namespace
// This test makes sure that the demangling method succeeds only on
// valid values of the string.
TEST_F(VFABIParserTest, OnlyValidNames) {
// Incomplete string.
EXPECT_FALSE(invokeParser(""));
EXPECT_FALSE(invokeParser("_ZGV"));
EXPECT_FALSE(invokeParser("_ZGVn"));
EXPECT_FALSE(invokeParser("_ZGVnN"));
EXPECT_FALSE(invokeParser("_ZGVnN2"));
EXPECT_FALSE(invokeParser("_ZGVnN2v"));
EXPECT_FALSE(invokeParser("_ZGVnN2v_"));
// Missing parameters.
EXPECT_FALSE(invokeParser("_ZGVnN2_foo"));
// Missing _ZGV prefix.
EXPECT_FALSE(invokeParser("_ZVnN2v_foo"));
// Missing <isa>.
EXPECT_FALSE(invokeParser("_ZGVN2v_foo"));
// Missing <mask>.
EXPECT_FALSE(invokeParser("_ZGVn2v_foo"));
// Missing <vlen>.
EXPECT_FALSE(invokeParser("_ZGVnNv_foo"));
// Missing <scalarname>.
EXPECT_FALSE(invokeParser("_ZGVnN2v_"));
// Missing _ separator.
EXPECT_FALSE(invokeParser("_ZGVnN2vfoo"));
// Missing <vectorname>. Using `fakename` because the string being
// parsed is not a valid function name that `invokeParser` can add.
EXPECT_FALSE(invokeParser("_ZGVnN2v_foo()", "fakename"));
// Unterminated name. Using `fakename` because the string being
// parsed is not a valid function name that `invokeParser` can add.
EXPECT_FALSE(invokeParser("_ZGVnN2v_foo(bar", "fakename"));
}
TEST_F(VFABIParserTest, ParamListParsing) {
EXPECT_TRUE(invokeParser("_ZGVnN2vl16Ls32R3l_foo"));
EXPECT_EQ(Parameters.size(), (unsigned)5);
EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector, 0}));
EXPECT_EQ(Parameters[1], VFParameter({1, VFParamKind::OMP_Linear, 16}));
EXPECT_EQ(Parameters[2], VFParameter({2, VFParamKind::OMP_LinearValPos, 32}));
EXPECT_EQ(Parameters[3], VFParameter({3, VFParamKind::OMP_LinearRef, 3}));
EXPECT_EQ(Parameters[4], VFParameter({4, VFParamKind::OMP_Linear, 1}));
}
TEST_F(VFABIParserTest, ScalarNameAndVectorName_01) {
EXPECT_TRUE(invokeParser("_ZGVnM2v_sin"));
EXPECT_EQ(ScalarName, "sin");
EXPECT_EQ(VectorName, "_ZGVnM2v_sin");
}
TEST_F(VFABIParserTest, ScalarNameAndVectorName_02) {
EXPECT_TRUE(invokeParser("_ZGVnM2v_sin(UserFunc)", "UserFunc"));
EXPECT_EQ(ScalarName, "sin");
EXPECT_EQ(VectorName, "UserFunc");
}
TEST_F(VFABIParserTest, ScalarNameAndVectorName_03) {
EXPECT_TRUE(invokeParser("_ZGVnM2v___sin_sin_sin"));
EXPECT_EQ(ScalarName, "__sin_sin_sin");
EXPECT_EQ(VectorName, "_ZGVnM2v___sin_sin_sin");
}
TEST_F(VFABIParserTest, Parse) { TEST_F(VFABIParserTest, Parse) {
EXPECT_TRUE(invokeParser("_ZGVnN2vls2Ls27Us4Rs5l1L10U100R1000_sin")); EXPECT_TRUE(invokeParser("_ZGVnN2vls2Ls27Us4Rs5l1L10U100R1000_sin"));
EXPECT_EQ(VF, (unsigned)2); EXPECT_EQ(VF, (unsigned)2);
@ -141,7 +180,7 @@ TEST_F(VFABIParserTest, Parse) {
} }
TEST_F(VFABIParserTest, ParseVectorName) { TEST_F(VFABIParserTest, ParseVectorName) {
EXPECT_TRUE(invokeParser("_ZGVnN2v_sin(my_v_sin)")); EXPECT_TRUE(invokeParser("_ZGVnN2v_sin(my_v_sin)", "my_v_sin"));
EXPECT_EQ(VF, (unsigned)2); EXPECT_EQ(VF, (unsigned)2);
EXPECT_FALSE(IsMasked()); EXPECT_FALSE(IsMasked());
EXPECT_FALSE(IsScalable); EXPECT_FALSE(IsScalable);
@ -168,13 +207,15 @@ TEST_F(VFABIParserTest, LinearWithCompileTimeNegativeStep) {
} }
TEST_F(VFABIParserTest, ParseScalableSVE) { TEST_F(VFABIParserTest, ParseScalableSVE) {
EXPECT_TRUE(invokeParser("_ZGVsMxv_sin")); EXPECT_TRUE(invokeParser(
EXPECT_EQ(VF, (unsigned)0); "_ZGVsMxv_sin(custom_vg)", "custom_vg",
"<vscale x 2 x i32>(<vscale x 2 x i32>, <vscale x 2 x i1>)"));
EXPECT_EQ(VF, (unsigned)2);
EXPECT_TRUE(IsMasked()); EXPECT_TRUE(IsMasked());
EXPECT_TRUE(IsScalable); EXPECT_TRUE(IsScalable);
EXPECT_EQ(ISA, VFISAKind::SVE); EXPECT_EQ(ISA, VFISAKind::SVE);
EXPECT_EQ(ScalarName, "sin"); EXPECT_EQ(ScalarName, "sin");
EXPECT_EQ(VectorName, "_ZGVsMxv_sin"); EXPECT_EQ(VectorName, "custom_vg");
} }
TEST_F(VFABIParserTest, ParseFixedWidthSVE) { TEST_F(VFABIParserTest, ParseFixedWidthSVE) {
@ -245,7 +286,7 @@ TEST_F(VFABIParserTest, ISA) {
TEST_F(VFABIParserTest, LLVM_ISA) { TEST_F(VFABIParserTest, LLVM_ISA) {
EXPECT_FALSE(invokeParser("_ZGV_LLVM_N2v_sin")); EXPECT_FALSE(invokeParser("_ZGV_LLVM_N2v_sin"));
EXPECT_TRUE(invokeParser("_ZGV_LLVM_N2v_sin_(vector_name)")); EXPECT_TRUE(invokeParser("_ZGV_LLVM_N2v_sin_(vector_name)", "vector_name"));
EXPECT_EQ(ISA, VFISAKind::LLVM); EXPECT_EQ(ISA, VFISAKind::LLVM);
} }
@ -353,8 +394,8 @@ TEST_F(VFABIParserTest, ISAIndependentMangling) {
EXPECT_EQ(VectorName, "_ZGVeN2vls2Ls27Us4Rs5l1L10U100R1000u2_sin"); EXPECT_EQ(VectorName, "_ZGVeN2vls2Ls27Us4Rs5l1L10U100R1000u2_sin");
// LLVM: <isa> = "_LLVM_" internal vector function. // LLVM: <isa> = "_LLVM_" internal vector function.
EXPECT_TRUE( EXPECT_TRUE(invokeParser(
invokeParser("_ZGV_LLVM_N2vls2Ls27Us4Rs5l1L10U100R1000u2_sin(vectorf)")); "_ZGV_LLVM_N2vls2Ls27Us4Rs5l1L10U100R1000u2_sin(vectorf)", "vectorf"));
EXPECT_EQ(ISA, VFISAKind::LLVM); EXPECT_EQ(ISA, VFISAKind::LLVM);
__COMMON_CHECKS; __COMMON_CHECKS;
EXPECT_EQ(VectorName, "vectorf"); EXPECT_EQ(VectorName, "vectorf");
@ -454,7 +495,8 @@ TEST_F(VFABIParserTest, ParseMaskingAVX512) {
} }
TEST_F(VFABIParserTest, ParseMaskingLLVM) { TEST_F(VFABIParserTest, ParseMaskingLLVM) {
EXPECT_TRUE(invokeParser("_ZGV_LLVM_M2v_sin(custom_vector_sin)")); EXPECT_TRUE(invokeParser("_ZGV_LLVM_M2v_sin(custom_vector_sin)",
"custom_vector_sin"));
EXPECT_EQ(VF, (unsigned)2); EXPECT_EQ(VF, (unsigned)2);
EXPECT_TRUE(IsMasked()); EXPECT_TRUE(IsMasked());
EXPECT_FALSE(IsScalable); EXPECT_FALSE(IsScalable);
@ -467,8 +509,11 @@ TEST_F(VFABIParserTest, ParseMaskingLLVM) {
} }
TEST_F(VFABIParserTest, ParseScalableMaskingLLVM) { TEST_F(VFABIParserTest, ParseScalableMaskingLLVM) {
EXPECT_TRUE(invokeParser("_ZGV_LLVM_Mxv_sin(custom_vector_sin)")); EXPECT_TRUE(invokeParser(
"_ZGV_LLVM_Mxv_sin(custom_vector_sin)", "custom_vector_sin",
"<vscale x 2 x i32> (<vscale x 2 x i32>, <vscale x 2 x i1>)"));
EXPECT_TRUE(IsMasked()); EXPECT_TRUE(IsMasked());
EXPECT_EQ(VF, (unsigned)2);
EXPECT_TRUE(IsScalable); EXPECT_TRUE(IsScalable);
EXPECT_EQ(ISA, VFISAKind::LLVM); EXPECT_EQ(ISA, VFISAKind::LLVM);
EXPECT_EQ(Parameters.size(), (unsigned)2); EXPECT_EQ(Parameters.size(), (unsigned)2);
@ -479,7 +524,10 @@ TEST_F(VFABIParserTest, ParseScalableMaskingLLVM) {
} }
TEST_F(VFABIParserTest, ParseScalableMaskingLLVMSincos) { TEST_F(VFABIParserTest, ParseScalableMaskingLLVMSincos) {
EXPECT_TRUE(invokeParser("_ZGV_LLVM_Mxvl8l8_sincos(custom_vector_sincos)")); EXPECT_TRUE(invokeParser("_ZGV_LLVM_Mxvl8l8_sincos(custom_vector_sincos)",
"custom_vector_sincos",
"void(<vscale x 2 x double>, double *, double *)"));
EXPECT_EQ(VF, (unsigned)2);
EXPECT_TRUE(IsMasked()); EXPECT_TRUE(IsMasked());
EXPECT_TRUE(IsScalable); EXPECT_TRUE(IsScalable);
EXPECT_EQ(ISA, VFISAKind::LLVM); EXPECT_EQ(ISA, VFISAKind::LLVM);
@ -528,12 +576,13 @@ TEST_F(VFABIAttrTest, Read) {
TEST_F(VFABIParserTest, LLVM_InternalISA) { TEST_F(VFABIParserTest, LLVM_InternalISA) {
EXPECT_FALSE(invokeParser("_ZGV_LLVM_N2v_sin")); EXPECT_FALSE(invokeParser("_ZGV_LLVM_N2v_sin"));
EXPECT_TRUE(invokeParser("_ZGV_LLVM_N2v_sin_(vector_name)")); EXPECT_TRUE(invokeParser("_ZGV_LLVM_N2v_sin_(vector_name)", "vector_name"));
EXPECT_EQ(ISA, VFISAKind::LLVM); EXPECT_EQ(ISA, VFISAKind::LLVM);
} }
TEST_F(VFABIParserTest, IntrinsicsInLLVMIsa) { TEST_F(VFABIParserTest, IntrinsicsInLLVMIsa) {
EXPECT_TRUE(invokeParser("_ZGV_LLVM_N4vv_llvm.pow.f32(__svml_powf4)")); EXPECT_TRUE(invokeParser("_ZGV_LLVM_N4vv_llvm.pow.f32(__svml_powf4)",
"__svml_powf4"));
EXPECT_EQ(VF, (unsigned)4); EXPECT_EQ(VF, (unsigned)4);
EXPECT_FALSE(IsMasked()); EXPECT_FALSE(IsMasked());
EXPECT_FALSE(IsScalable); EXPECT_FALSE(IsScalable);
@ -543,3 +592,20 @@ TEST_F(VFABIParserTest, IntrinsicsInLLVMIsa) {
EXPECT_EQ(Parameters[1], VFParameter({1, VFParamKind::Vector})); EXPECT_EQ(Parameters[1], VFParameter({1, VFParamKind::Vector}));
EXPECT_EQ(ScalarName, "llvm.pow.f32"); EXPECT_EQ(ScalarName, "llvm.pow.f32");
} }
TEST_F(VFABIParserTest, ParseScalableRequiresDeclaration) {
const char *MangledName = "_ZGVsMxv_sin(custom_vg)";
// The parser succeds only when the correct function definition of
// `custom_vg` is added to the module.
EXPECT_FALSE(invokeParser(MangledName));
EXPECT_TRUE(invokeParser(
MangledName, "custom_vg",
"<vscale x 4 x double>(<vscale x 4 x double>, <vscale x 4 x i1>)"));
}
TEST_F(VFABIParserTest, ZeroIsInvalidVLEN) {
EXPECT_FALSE(invokeParser("_ZGVeM0v_sin"));
EXPECT_FALSE(invokeParser("_ZGVeN0v_sin"));
EXPECT_FALSE(invokeParser("_ZGVsM0v_sin"));
EXPECT_FALSE(invokeParser("_ZGVsN0v_sin"));
}