-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[VFABI] Create FunctionType for vector functions #75058
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[VFABI] Create FunctionType for vector functions #75058
Conversation
`createFunctionType` optionally returns a FunctionType and the mask's position when there's one. It requires VFInfo and an Instruction. Add `checkFunctionType` in 'VectorFunctionABITest.cpp' tests to check that both the number and the type of vectorized parameters matches the created `FunctionType`.
@llvm/pr-subscribers-llvm-analysis Author: Paschalis Mpeis (paschalis-mpeis) Changes
Add Patch is 22.21 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/75058.diff 4 Files Affected:
diff --git a/llvm/include/llvm/Analysis/VectorUtils.h b/llvm/include/llvm/Analysis/VectorUtils.h
index 55a6aa645a86e2..734c440283b4a0 100644
--- a/llvm/include/llvm/Analysis/VectorUtils.h
+++ b/llvm/include/llvm/Analysis/VectorUtils.h
@@ -195,6 +195,13 @@ static constexpr char const *MappingsAttrName = "vector-function-abi-variant";
/// the presence of the attribute (see InjectTLIMappings).
void getVectorVariantNames(const CallInst &CI,
SmallVectorImpl<std::string> &VariantMappings);
+
+/// Returns a pair of the vectorized FunctionType and the mask's position when
+/// there's one, otherwise -1. It rejects any non vectorized calls as this
+/// method should be called at a point where the Instruction \p I is already
+/// vectorized.
+std::optional<std::pair<FunctionType *, int>>
+createFunctionType(const VFInfo &Info, const Instruction *I, const Module *M);
} // end namespace VFABI
/// The Vector Function Database.
diff --git a/llvm/lib/Analysis/VFABIDemangling.cpp b/llvm/lib/Analysis/VFABIDemangling.cpp
index 92af314a41caad..fc94a33851963c 100644
--- a/llvm/lib/Analysis/VFABIDemangling.cpp
+++ b/llvm/lib/Analysis/VFABIDemangling.cpp
@@ -376,7 +376,7 @@ std::optional<VFInfo> VFABI::tryDemangleForVFABI(StringRef MangledName,
// _ZGV<isa><mask><vlen><parameters>_<scalarname>.
StringRef VectorName = MangledName;
- // Parse the fixed size part of the manled name
+ // Parse the fixed size part of the mangled name
if (!MangledName.consume_front("_ZGV"))
return std::nullopt;
diff --git a/llvm/lib/Analysis/VectorUtils.cpp b/llvm/lib/Analysis/VectorUtils.cpp
index 91d8c31fa062de..c31f0f3bd2fd58 100644
--- a/llvm/lib/Analysis/VectorUtils.cpp
+++ b/llvm/lib/Analysis/VectorUtils.cpp
@@ -12,6 +12,7 @@
#include "llvm/Analysis/VectorUtils.h"
#include "llvm/ADT/EquivalenceClasses.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/DemandedBits.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/LoopIterator.h"
@@ -24,6 +25,7 @@
#include "llvm/IR/PatternMatch.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/CommandLine.h"
+#include <optional>
#define DEBUG_TYPE "vectorutils"
@@ -1477,6 +1479,49 @@ void VFABI::getVectorVariantNames(
}
}
+// Returns whether any of the operands or return type of \p I are vectors.
+static bool isVectorized(const Instruction *I) {
+ if (I->getType()->isVectorTy())
+ return true;
+ for (auto &U : I->operands())
+ if (U->getType()->isVectorTy())
+ return true;
+ return false;
+}
+
+std::optional<std::pair<FunctionType *, int>>
+VFABI::createFunctionType(const VFInfo &Info, const Instruction *I,
+ const Module *M) {
+ // only vectorized calls should reach this method
+ if (!isVectorized(I))
+ return std::nullopt;
+
+ ElementCount VF = Info.Shape.VF;
+ // get vectorized operands
+ const bool IsCall = isa<CallBase>(I);
+ SmallVector<Type *, 8> VecParams;
+ for (auto [i, U] : enumerate(I->operands())) {
+ // ignore the function pointer when the Instruction is a call
+ if (IsCall && i == I->getNumOperands() - 1)
+ break;
+ VecParams.push_back(U->getType());
+ }
+
+ // Append a mask and get its position.
+ int MaskPos = -1;
+ if (Info.isMasked()) {
+ auto OptMaskPos = Info.getParamIndexForOptionalMask();
+ if (!OptMaskPos)
+ return std::nullopt;
+
+ MaskPos = OptMaskPos.value();
+ VectorType *MaskTy = VectorType::get(Type::getInt1Ty(M->getContext()), VF);
+ VecParams.insert(VecParams.begin() + MaskPos, MaskTy);
+ }
+ FunctionType *VecFTy = FunctionType::get(I->getType(), VecParams, false);
+ return std::make_pair(VecFTy, MaskPos);
+}
+
bool VFShape::hasValidParameterList() const {
for (unsigned Pos = 0, NumParams = Parameters.size(); Pos < NumParams;
++Pos) {
diff --git a/llvm/unittests/Analysis/VectorFunctionABITest.cpp b/llvm/unittests/Analysis/VectorFunctionABITest.cpp
index 201dd1127ef234..85177db74ef585 100644
--- a/llvm/unittests/Analysis/VectorFunctionABITest.cpp
+++ b/llvm/unittests/Analysis/VectorFunctionABITest.cpp
@@ -11,6 +11,7 @@
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/InstIterator.h"
#include "gtest/gtest.h"
+#include <optional>
using namespace llvm;
@@ -91,6 +92,77 @@ class VFABIParserTest : public ::testing::Test {
bool matchParametersNum() {
return (Parameters.size() - isMasked()) == ScalarFTy->getNumParams();
}
+
+ /// Creates a mock CallInst and uses it along with VFInfo to create a
+ /// FunctionType. Then it checks that the created FunctionType matches the
+ /// number and type of arguments with both the ScalarFTy and the operands of
+ /// the call.
+ bool checkFunctionType() {
+ // Create a mock vectorized CallInst using dummy values and then use it to
+ // create a vector FunctionType. In the case of scalable ISAs, the created
+ // vector FunctionType might have a mask parameter Type, however, this input
+ // CallInst will not have a mask operand.
+ SmallVector<Value *, 8> Args;
+ SmallVector<Type *, 8> CallTypes;
+ for (auto [VFParam, STy] :
+ zip(Info.Shape.Parameters, ScalarFTy->params())) {
+ // use VectorType where relevant, according to VShape
+ Type *UseTy = STy;
+ if (VFParam.ParamKind == VFParamKind::Vector)
+ UseTy = VectorType::get(STy, Info.Shape.VF);
+
+ CallTypes.push_back(UseTy);
+ Args.push_back(Constant::getNullValue(UseTy));
+ }
+
+ // Mangled names do not currently encode return Type information. Generally,
+ // return types are vectors, so use one.
+ Type *RetTy = ScalarFTy->getReturnType();
+ if (!RetTy->isVoidTy())
+ RetTy = VectorType::get(RetTy, Info.Shape.VF);
+
+ FunctionCallee F = M->getOrInsertFunction(
+ VectorName, FunctionType::get(RetTy, CallTypes, false));
+ std::unique_ptr<CallInst> CI(CallInst::Create(F, Args));
+
+ // Use VFInfo and the mock CallInst to create a FunctionType that will
+ // include a mask where relevant.
+ auto OptVecFTyPos = VFABI::createFunctionType(Info, CI.get(), M.get());
+ if (!OptVecFTyPos)
+ return false;
+
+ FunctionType *VecFTy = OptVecFTyPos->first;
+ // Check that vectorized parameters' size match with VFInfo.
+ // Both may include a mask.
+ if ((VecFTy->getNumParams() != Info.Shape.Parameters.size()))
+ return false;
+
+ // Check if the types of the vectorized parameters from the created
+ // FunctionType match with the arguments passed to the CallInst. Any masks
+ // are ignored, as the original, mock CallInst does not have one.
+ auto VecParams = VecFTy->params();
+ for (auto [VecTy, VFTyParam] : zip(CallTypes, VecParams))
+ if (VecTy != VFTyParam)
+ return false;
+
+ // Check if the types of the scalar and vector FunctionTypes match.
+ // In the case of a mask, the vector FunctionType should have an additional
+ // i1 vector parameter.
+ if (ScalarFTy->getReturnType() != VecFTy->getReturnType()->getScalarType())
+ return false;
+ auto ScalarParams = ScalarFTy->params();
+ for (auto [OptSTy, OptVTy] : zip_longest(ScalarParams, VecParams)) {
+ Type *VTy = OptVTy.value();
+ // ensure the extra vector Type is a mask
+ if (!OptSTy && VTy->isVectorTy() &&
+ VTy->getScalarType() != Type::getInt1Ty(M->getContext()))
+ return false;
+ if (OptSTy && OptSTy.value() != VTy->getScalarType())
+ return false;
+ }
+
+ return true;
+ }
};
} // unnamed namespace
@@ -130,7 +202,8 @@ TEST_F(VFABIParserTest, ParamListParsing) {
invokeParser("_ZGVnN2vl16Ls32R3l_foo", "void(i32, i32, i32, ptr, i32)"));
EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
EXPECT_EQ(false, isMasked());
- EXPECT_TRUE(matchParametersNum()) << "Different number of scalar parameters";
+ EXPECT_TRUE(matchParametersNum());
+ EXPECT_TRUE(checkFunctionType());
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}));
@@ -145,7 +218,8 @@ TEST_F(VFABIParserTest, ScalarNameAndVectorName_01) {
EXPECT_TRUE(invokeParser("_ZGVnM2v_foo(vector_foo)", "void(i32)"));
EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
EXPECT_EQ(true, isMasked());
- EXPECT_TRUE(matchParametersNum()) << "Different number of scalar parameters";
+ EXPECT_TRUE(matchParametersNum());
+ EXPECT_TRUE(checkFunctionType());
EXPECT_EQ(ScalarName, "foo");
EXPECT_EQ(VectorName, "vector_foo");
}
@@ -154,7 +228,8 @@ TEST_F(VFABIParserTest, ScalarNameAndVectorName_02) {
EXPECT_TRUE(invokeParser("_ZGVnM2v_foo(vector_foo)", "void(i32)"));
EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
EXPECT_EQ(true, isMasked());
- EXPECT_TRUE(matchParametersNum()) << "Different number of scalar parameters";
+ EXPECT_TRUE(matchParametersNum());
+ EXPECT_TRUE(checkFunctionType());
EXPECT_EQ(ScalarName, "foo");
EXPECT_EQ(VectorName, "vector_foo");
}
@@ -164,7 +239,8 @@ TEST_F(VFABIParserTest, ScalarNameAndVectorName_03) {
invokeParser("_ZGVnM2v___foo_bar_abc(fooBarAbcVec)", "void(i32)"));
EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
EXPECT_EQ(true, isMasked());
- EXPECT_TRUE(matchParametersNum()) << "Different number of scalar parameters";
+ EXPECT_TRUE(matchParametersNum());
+ EXPECT_TRUE(checkFunctionType());
EXPECT_EQ(ScalarName, "__foo_bar_abc");
EXPECT_EQ(VectorName, "fooBarAbcVec");
}
@@ -185,7 +261,8 @@ TEST_F(VFABIParserTest, Parse) {
"void(i32, i32, i32, i32, ptr, i32, i32, i32, ptr)"));
EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
EXPECT_FALSE(isMasked());
- EXPECT_TRUE(matchParametersNum()) << "Different number of scalar parameters";
+ EXPECT_TRUE(matchParametersNum());
+ EXPECT_TRUE(checkFunctionType());
EXPECT_EQ(VF, ElementCount::getFixed(2));
EXPECT_EQ(Parameters.size(), (unsigned)9);
EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector, 0}));
@@ -205,7 +282,8 @@ TEST_F(VFABIParserTest, ParseVectorName) {
EXPECT_TRUE(invokeParser("_ZGVnN2v_foo(vector_foo)", "void(i32)"));
EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
EXPECT_FALSE(isMasked());
- EXPECT_TRUE(matchParametersNum()) << "Different number of scalar parameters";
+ EXPECT_TRUE(matchParametersNum());
+ EXPECT_TRUE(checkFunctionType());
EXPECT_EQ(VF, ElementCount::getFixed(2));
EXPECT_EQ(Parameters.size(), (unsigned)1);
EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector, 0}));
@@ -218,7 +296,8 @@ TEST_F(VFABIParserTest, LinearWithCompileTimeNegativeStep) {
"void(i32, i32, i32, ptr)"));
EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
EXPECT_FALSE(isMasked());
- EXPECT_TRUE(matchParametersNum()) << "Different number of scalar parameters";
+ EXPECT_TRUE(matchParametersNum());
+ EXPECT_FALSE(checkFunctionType()); // invalid: all operands are scalar
EXPECT_EQ(VF, ElementCount::getFixed(2));
EXPECT_EQ(Parameters.size(), (unsigned)4);
EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::OMP_Linear, -1}));
@@ -233,7 +312,8 @@ TEST_F(VFABIParserTest, ParseScalableSVE) {
EXPECT_TRUE(invokeParser("_ZGVsMxv_foo(vector_foo)", "void(i32)"));
EXPECT_EQ(ISA, VFISAKind::SVE);
EXPECT_TRUE(isMasked());
- EXPECT_TRUE(matchParametersNum()) << "Different number of scalar parameters";
+ EXPECT_TRUE(matchParametersNum());
+ EXPECT_TRUE(checkFunctionType());
EXPECT_EQ(VF, ElementCount::getScalable(4));
EXPECT_EQ(Parameters.size(), (unsigned)2);
EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
@@ -246,7 +326,8 @@ TEST_F(VFABIParserTest, ParseFixedWidthSVE) {
EXPECT_TRUE(invokeParser("_ZGVsM2v_foo(vector_foo)", "void(i32)"));
EXPECT_EQ(ISA, VFISAKind::SVE);
EXPECT_TRUE(isMasked());
- EXPECT_TRUE(matchParametersNum()) << "Different number of scalar parameters";
+ EXPECT_TRUE(matchParametersNum());
+ EXPECT_TRUE(checkFunctionType());
EXPECT_EQ(VF, ElementCount::getFixed(2));
EXPECT_EQ(Parameters.size(), (unsigned)2);
EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
@@ -280,7 +361,8 @@ TEST_F(VFABIParserTest, LinearWithoutCompileTime) {
"void(i32, i32, ptr, i32, i32, i32, ptr, i32)"));
EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
EXPECT_FALSE(isMasked());
- EXPECT_TRUE(matchParametersNum()) << "Different number of scalar parameters";
+ EXPECT_TRUE(matchParametersNum());
+ EXPECT_FALSE(checkFunctionType()); // invalid: all operands are scalar
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}));
@@ -299,7 +381,8 @@ TEST_F(VFABIParserTest, LLVM_ISA) {
EXPECT_TRUE(invokeParser("_ZGV_LLVM_N2v_foo(vector_foo)", "void(i32)"));
EXPECT_EQ(ISA, VFISAKind::LLVM);
EXPECT_FALSE(isMasked());
- EXPECT_TRUE(matchParametersNum()) << "Different number of scalar parameters";
+ EXPECT_TRUE(matchParametersNum());
+ EXPECT_TRUE(checkFunctionType());
EXPECT_EQ(Parameters.size(), (unsigned)1);
EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
EXPECT_EQ(ScalarName, "foo");
@@ -318,7 +401,7 @@ TEST_F(VFABIParserTest, Align) {
EXPECT_TRUE(invokeParser("_ZGVsN2l2a2_foo(vector_foo)", "void(i32)"));
EXPECT_EQ(ISA, VFISAKind::SVE);
EXPECT_FALSE(isMasked());
- EXPECT_TRUE(matchParametersNum()) << "Different number of scalar parameters";
+ EXPECT_TRUE(matchParametersNum());
EXPECT_EQ(Parameters.size(), (unsigned)1);
EXPECT_EQ(Parameters[0].Alignment, Align(2));
EXPECT_EQ(ScalarName, "foo");
@@ -341,7 +424,8 @@ TEST_F(VFABIParserTest, ParseUniform) {
EXPECT_TRUE(invokeParser("_ZGVnN2u_foo(vector_foo)", "void(i32)"));
EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
EXPECT_FALSE(isMasked());
- EXPECT_TRUE(matchParametersNum()) << "Different number of scalar parameters";
+ EXPECT_TRUE(matchParametersNum());
+ EXPECT_FALSE(checkFunctionType()); // invalid: all operands are scalar
EXPECT_EQ(VF, ElementCount::getFixed(2));
EXPECT_EQ(Parameters.size(), (unsigned)1);
EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::OMP_Uniform, 0}));
@@ -374,8 +458,8 @@ TEST_F(VFABIParserTest, ISAIndependentMangling) {
do { \
EXPECT_EQ(VF, ElementCount::getFixed(2)); \
EXPECT_FALSE(isMasked()); \
- EXPECT_TRUE(matchParametersNum()) \
- << "Different number of scalar parameters"; \
+ EXPECT_TRUE(matchParametersNum()); \
+ EXPECT_TRUE(checkFunctionType()); \
EXPECT_EQ(Parameters.size(), (unsigned)10); \
EXPECT_EQ(Parameters, ExpectedParams); \
EXPECT_EQ(ScalarName, "foo"); \
@@ -450,7 +534,8 @@ TEST_F(VFABIParserTest, ParseMaskingNEON) {
EXPECT_TRUE(invokeParser("_ZGVnM2v_foo(vector_foo)", "void(i32)"));
EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
EXPECT_TRUE(isMasked());
- EXPECT_TRUE(matchParametersNum()) << "Different number of scalar parameters";
+ EXPECT_TRUE(matchParametersNum());
+ EXPECT_TRUE(checkFunctionType());
EXPECT_EQ(VF, ElementCount::getFixed(2));
EXPECT_EQ(Parameters.size(), (unsigned)2);
EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
@@ -463,7 +548,8 @@ TEST_F(VFABIParserTest, ParseMaskingSVE) {
EXPECT_TRUE(invokeParser("_ZGVsM2v_foo(vector_foo)", "void(i32)"));
EXPECT_EQ(ISA, VFISAKind::SVE);
EXPECT_TRUE(isMasked());
- EXPECT_TRUE(matchParametersNum()) << "Different number of scalar parameters";
+ EXPECT_TRUE(matchParametersNum());
+ EXPECT_TRUE(checkFunctionType());
EXPECT_EQ(VF, ElementCount::getFixed(2));
EXPECT_EQ(Parameters.size(), (unsigned)2);
EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
@@ -476,7 +562,8 @@ TEST_F(VFABIParserTest, ParseMaskingSSE) {
EXPECT_TRUE(invokeParser("_ZGVbM2v_foo(vector_foo)", "void(i32)"));
EXPECT_EQ(ISA, VFISAKind::SSE);
EXPECT_TRUE(isMasked());
- EXPECT_TRUE(matchParametersNum()) << "Different number of scalar parameters";
+ EXPECT_TRUE(matchParametersNum());
+ EXPECT_TRUE(checkFunctionType());
EXPECT_EQ(VF, ElementCount::getFixed(2));
EXPECT_EQ(Parameters.size(), (unsigned)2);
EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
@@ -489,7 +576,8 @@ TEST_F(VFABIParserTest, ParseMaskingAVX) {
EXPECT_TRUE(invokeParser("_ZGVcM2v_foo(vector_foo)", "void(i32)"));
EXPECT_EQ(ISA, VFISAKind::AVX);
EXPECT_TRUE(isMasked());
- EXPECT_TRUE(matchParametersNum()) << "Different number of scalar parameters";
+ EXPECT_TRUE(matchParametersNum());
+ EXPECT_TRUE(checkFunctionType());
EXPECT_EQ(VF, ElementCount::getFixed(2));
EXPECT_EQ(Parameters.size(), (unsigned)2);
EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
@@ -502,7 +590,8 @@ TEST_F(VFABIParserTest, ParseMaskingAVX2) {
EXPECT_TRUE(invokeParser("_ZGVdM2v_foo(vector_foo)", "void(i32)"));
EXPECT_EQ(ISA, VFISAKind::AVX2);
EXPECT_TRUE(isMasked());
- EXPECT_TRUE(matchParametersNum()) << "Different number of scalar parameters";
+ EXPECT_TRUE(matchParametersNum());
+ EXPECT_TRUE(checkFunctionType());
EXPECT_EQ(VF, ElementCount::getFixed(2));
EXPECT_EQ(Parameters.size(), (unsigned)2);
EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
@@ -515,7 +604,8 @@ TEST_F(VFABIParserTest, ParseMaskingAVX512) {
EXPECT_TRUE(invokeParser("_ZGVeM2v_foo(vector_foo)", "void(i32)"));
EXPECT_EQ(ISA, VFISAKind::AVX512);
EXPECT_TRUE(isMasked());
- EXPECT_TRUE(matchParametersNum()) << "Different number of scalar parameters";
+ EXPECT_TRUE(matchParametersNum());
+ EXPECT_TRUE(checkFunctionType());
EXPECT_EQ(VF, ElementCount::getFixed(2));
EXPECT_EQ(Parameters.size(), (unsigned)2);
EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
@@ -528,7 +618,8 @@ TEST_F(VFABIParserTest, ParseMaskingLLVM) {
EXPECT_TRUE(invokeParser("_ZGV_LLVM_M2v_foo(vector_foo)", "void(i32)"));
EXPECT_EQ(ISA, VFISAKind::LLVM);
EXPECT_TRUE(isMasked());
- EXPECT_TRUE(matchParametersNum()) << "Different number of scalar parameters";
+ EXPECT_TRUE(matchParametersNum());
+ EXPECT_TRUE(checkFunctionType());
EXPECT_EQ(VF, ElementCount::getFixed(2));
EXPECT_EQ(Parameters.size(), (unsigned)2);
EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
@@ -546,7 +637,8 @@ TEST_F(VFABIParserTest, LLVM_InternalISA) {
EXPECT_TRUE(invokeParser("_ZGV_LLVM_N2v_foo(vector_foo)", "void(i32)"));
EXPECT_EQ(ISA, VFISAKind::LLVM);
EXPECT_FALSE(isMasked());
- EXPECT_TRUE(matchParametersNum()) << "Different number of scalar parameters";
+ EXPECT_TRUE(matchParametersNum());
+ EXPECT_TRUE(checkFunctionType());
EXPECT_EQ(Parameters.size(), (unsigned)1);
EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
EXPECT_EQ(ScalarName, "foo");
@@ -558,7 +650,8 @@ TEST_F(VFABIParserTest, IntrinsicsInLLVMIsa) {
"void(float, float)"));
EXPECT_EQ(ISA, VFISAKind::LLVM);
EXPECT_FALSE(isMasked());
- EXPECT_TRUE(matchParametersNum()) << "Different number of scalar parameters";
+ EXPECT_TRUE(matchParametersNum());
+ EXPECT_TRUE(checkFunctionType());
EXPECT_EQ(VF, ElementCount::getFixed(4));
EXPECT_EQ(Parameters.size(), (unsigned)2);
EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
@@ -573,7 +666,8 @@ TEST_F(VFABIParserTest, ParseScalableRequiresDeclaration) {
EXPECT_TRUE(invokeParser(MangledName, "void(i32)"));
EXPECT_EQ(ISA, VFISAKind::SVE);
EXPECT_TRUE(isMasked());
- EXPECT_TRUE(matchParametersNum()) << "Different number of scalar parameters";
+ EXPECT_TRUE(matchParametersNum());
+ EXPECT_TRUE(checkFunctionType());
EXPECT_EQ(Parameters.size(), (unsigned)2);
EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
EXPECT_EQ(Parameters[1], VFParameter({1, VFParamKind::GlobalPredicate}));
@@ -592,7 +686,8 @@ TEST_F(VFABIParserTest, ParseScalableMaskingSVE) {
EXPECT_TRUE(invokeParser("_ZGVsMxv_foo(vector_foo)", "i32(i32)"));
EXPECT_EQ(ISA, VFISAKind::SVE);
...
[truncated]
|
'createFunctionType' should be able to create the correct FunctionType, regardless of whether the input Instruction was masked or not. It uses VFInfo to figure out if the input Instruction was already masked, and if so it does not append another mask Type. In checks, create two mock CallInsts, one with a mask and one without and verify that they have the same number of parameters.
It accepts ScalarFTy and VecRetTy. As the latter is not kept in VFABI, it should instead come from the original Instruction/Callinst. This change allows further simplification in tests. Also, methods like the test `_ZGVnN3lLRUlnLnRnUn_foo`, which contains only scalar parameters, would still return a valid FunctionType. This is an edge case that will only be encountered in tests though.
Not returning a pair anymore as the position can be queries directly from VFInfo, which createFunctionType needs to have as an argument to begin with. Also getting the return type from the ScalarFTy, as the specification does not encode in the mangled name such information. Therefore, the VFInfo does not hold such info. If that changes, then it will make its way into VFInfo and one could get it from there.
Refactored 'createFunctionType'
If the VFABI specification changes, allowing vectors in any position other than the end of the argument list, createFunctionType should now be able to handle it.
createFunctionType
optionally returns a FunctionType and the mask's position when there's one. It requires VFInfo and an Instruction.Add
checkFunctionType
in 'VectorFunctionABITest.cpp' tests to check that both the number and the type of vectorized parameters matches the createdFunctionType
.