[llvm] [VFABI] Create FunctionType for vector functions (PR #75058)

Paschalis Mpeis via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 18 06:02:38 PST 2023


https://github.com/paschalis-mpeis updated https://github.com/llvm/llvm-project/pull/75058

>From 73d59dd54cc972bab2fac190973da010289c25ea Mon Sep 17 00:00:00 2001
From: Paschalis Mpeis <Paschalis.Mpeis at arm.com>
Date: Fri, 1 Dec 2023 17:56:59 +0000
Subject: [PATCH 1/7] [VFABI] Create FunctionType for vector functions

`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/include/llvm/Analysis/VectorUtils.h      |   7 +
 llvm/lib/Analysis/VFABIDemangling.cpp         |   2 +-
 llvm/lib/Analysis/VectorUtils.cpp             |  45 +++++
 .../Analysis/VectorFunctionABITest.cpp        | 157 ++++++++++++++----
 4 files changed, 181 insertions(+), 30 deletions(-)

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);
   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}));
@@ -606,7 +701,8 @@ TEST_F(VFABIParserTest, ParseScalableMaskingSVESincos) {
                            "void(double, ptr, ptr)"));
   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(2));
   EXPECT_EQ(Parameters.size(), (unsigned)4);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
@@ -623,7 +719,8 @@ TEST_F(VFABIParserTest, ParseWiderReturnTypeSVE) {
   EXPECT_TRUE(invokeParser("_ZGVsMxvv_foo(vector_foo)", "i64(i32, 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)3);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
   EXPECT_EQ(Parameters[1], VFParameter({1, VFParamKind::Vector}));
@@ -638,7 +735,8 @@ TEST_F(VFABIParserTest, ParseVoidReturnTypeSVE) {
   EXPECT_TRUE(invokeParser("_ZGVsMxv_foo(vector_foo)", "void(i16)"));
   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}));
@@ -656,6 +754,7 @@ TEST_F(VFABIParserTest, ParseUnsupportedElementTypeSVE) {
 TEST_F(VFABIParserTest, ParseUnsupportedReturnTypeSVE) {
   EXPECT_FALSE(invokeParser("_ZGVsMxv_foo(vector_foo)", "fp128(float)"));
 }
+
 class VFABIAttrTest : public testing::Test {
 protected:
   void SetUp() override {

>From c95fe95111af988881865a327fd5641d9ca6239d Mon Sep 17 00:00:00 2001
From: Paschalis Mpeis <Paschalis.Mpeis at arm.com>
Date: Mon, 11 Dec 2023 18:02:37 +0000
Subject: [PATCH 2/7] Handle already masked Instructions.

'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.
---
 llvm/lib/Analysis/VectorUtils.cpp             | 10 ++++---
 .../Analysis/VectorFunctionABITest.cpp        | 27 +++++++++++++++++++
 2 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Analysis/VectorUtils.cpp b/llvm/lib/Analysis/VectorUtils.cpp
index c31f0f3bd2fd58..f4dc26da812250 100644
--- a/llvm/lib/Analysis/VectorUtils.cpp
+++ b/llvm/lib/Analysis/VectorUtils.cpp
@@ -1507,7 +1507,7 @@ VFABI::createFunctionType(const VFInfo &Info, const Instruction *I,
     VecParams.push_back(U->getType());
   }
 
-  // Append a mask and get its position.
+  // Get mask's position mask and append one if not present in the Instruction.
   int MaskPos = -1;
   if (Info.isMasked()) {
     auto OptMaskPos = Info.getParamIndexForOptionalMask();
@@ -1515,8 +1515,12 @@ VFABI::createFunctionType(const VFInfo &Info, const Instruction *I,
       return std::nullopt;
 
     MaskPos = OptMaskPos.value();
-    VectorType *MaskTy = VectorType::get(Type::getInt1Ty(M->getContext()), VF);
-    VecParams.insert(VecParams.begin() + MaskPos, MaskTy);
+    // append a mask only when it's missing
+    if (VecParams.size() == Info.Shape.Parameters.size() - 1) {
+      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);
diff --git a/llvm/unittests/Analysis/VectorFunctionABITest.cpp b/llvm/unittests/Analysis/VectorFunctionABITest.cpp
index 85177db74ef585..8daebb6042156d 100644
--- a/llvm/unittests/Analysis/VectorFunctionABITest.cpp
+++ b/llvm/unittests/Analysis/VectorFunctionABITest.cpp
@@ -131,6 +131,33 @@ class VFABIParserTest : public ::testing::Test {
     if (!OptVecFTyPos)
       return false;
 
+    // Ensure that masked Instructions are handled
+    if (isMasked()) {
+      // In case of a masked call, try creating another mock CallInst that is
+      // masked. createFunctionType should be able to handle this.
+      SmallVector<Type *, 8> CallTypesInclMask(CallTypes);
+      SmallVector<Value *, 8> ArgsInclMask(Args);
+      Type *MaskTy = VectorType::get(Type::getInt1Ty(M->getContext()), VF);
+      CallTypesInclMask.push_back(MaskTy);
+      ArgsInclMask.push_back(Constant::getNullValue(MaskTy));
+
+      FunctionCallee FMasked = M->getOrInsertFunction(
+          VectorName + "_Masked",
+          FunctionType::get(RetTy, CallTypesInclMask, false));
+      std::unique_ptr<CallInst> CIMasked(
+          CallInst::Create(FMasked, ArgsInclMask));
+      auto OptVecFTyMaskedPos =
+          VFABI::createFunctionType(Info, CIMasked.get(), M.get());
+      if (!OptVecFTyMaskedPos)
+        return false;
+
+      // Both FunctionTypes should have the same number of parameters.
+      assert(
+          (OptVecFTyPos->first->getNumParams() ==
+           OptVecFTyMaskedPos->first->getNumParams()) &&
+          "createFunctionType should accept masked or non masked Instructions");
+    }
+
     FunctionType *VecFTy = OptVecFTyPos->first;
     // Check that vectorized parameters' size match with VFInfo.
     // Both may include a mask.

>From c07a3dabe1e63b53498b84da6d0f04a522d79d86 Mon Sep 17 00:00:00 2001
From: Paschalis Mpeis <Paschalis.Mpeis at arm.com>
Date: Tue, 12 Dec 2023 17:33:18 +0000
Subject: [PATCH 3/7] Simplified createFunctionType method

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.
---
 llvm/include/llvm/Analysis/VectorUtils.h      |  7 ++-
 llvm/lib/Analysis/VectorUtils.cpp             | 43 +++++----------
 .../Analysis/VectorFunctionABITest.cpp        | 53 +++++--------------
 3 files changed, 28 insertions(+), 75 deletions(-)

diff --git a/llvm/include/llvm/Analysis/VectorUtils.h b/llvm/include/llvm/Analysis/VectorUtils.h
index 734c440283b4a0..6b3a001f7c6070 100644
--- a/llvm/include/llvm/Analysis/VectorUtils.h
+++ b/llvm/include/llvm/Analysis/VectorUtils.h
@@ -197,11 +197,10 @@ 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.
+/// there's one, otherwise -1.
 std::optional<std::pair<FunctionType *, int>>
-createFunctionType(const VFInfo &Info, const Instruction *I, const Module *M);
+createFunctionType(const VFInfo &Info, const FunctionType *ScalarFTy,
+                   Type *VecRetTy, const Module *M);
 } // end namespace VFABI
 
 /// The Vector Function Database.
diff --git a/llvm/lib/Analysis/VectorUtils.cpp b/llvm/lib/Analysis/VectorUtils.cpp
index f4dc26da812250..19529e0f012a30 100644
--- a/llvm/lib/Analysis/VectorUtils.cpp
+++ b/llvm/lib/Analysis/VectorUtils.cpp
@@ -1479,32 +1479,17 @@ 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;
-
+VFABI::createFunctionType(const VFInfo &Info, const FunctionType *ScalarFTy,
+                          Type *VecRetTy, const Module *M) {
   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());
+  // Create vector parameter types
+  SmallVector<Type *, 8> VecTypes;
+  for (auto [STy, VFParam] : zip(ScalarFTy->params(), Info.Shape.Parameters)) {
+    if (VFParam.ParamKind == VFParamKind::Vector)
+      VecTypes.push_back(VectorType::get(STy, VF));
+    else
+      VecTypes.push_back(STy);
   }
 
   // Get mask's position mask and append one if not present in the Instruction.
@@ -1515,14 +1500,10 @@ VFABI::createFunctionType(const VFInfo &Info, const Instruction *I,
       return std::nullopt;
 
     MaskPos = OptMaskPos.value();
-    // append a mask only when it's missing
-    if (VecParams.size() == Info.Shape.Parameters.size() - 1) {
-      VectorType *MaskTy =
-          VectorType::get(Type::getInt1Ty(M->getContext()), VF);
-      VecParams.insert(VecParams.begin() + MaskPos, MaskTy);
-    }
+    VectorType *MaskTy = VectorType::get(Type::getInt1Ty(M->getContext()), VF);
+    VecTypes.insert(VecTypes.begin() + MaskPos, MaskTy);
   }
-  FunctionType *VecFTy = FunctionType::get(I->getType(), VecParams, false);
+  FunctionType *VecFTy = FunctionType::get(VecRetTy, VecTypes, false);
   return std::make_pair(VecFTy, MaskPos);
 }
 
diff --git a/llvm/unittests/Analysis/VectorFunctionABITest.cpp b/llvm/unittests/Analysis/VectorFunctionABITest.cpp
index 8daebb6042156d..e02a3b1c03c1f5 100644
--- a/llvm/unittests/Analysis/VectorFunctionABITest.cpp
+++ b/llvm/unittests/Analysis/VectorFunctionABITest.cpp
@@ -98,10 +98,9 @@ class VFABIParserTest : public ::testing::Test {
   /// 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.
+    // For scalable ISAs, the created vector FunctionType might have a mask
+    // parameter Type, according to VFABI. Regardless, this input CallInst,
+    // despite being a vectorized call, it will not have a masked operand.
     SmallVector<Value *, 8> Args;
     SmallVector<Type *, 8> CallTypes;
     for (auto [VFParam, STy] :
@@ -117,47 +116,21 @@ class VFABIParserTest : public ::testing::Test {
 
     // 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);
+    Type *VecRetTy = ScalarFTy->getReturnType();
+    if (!VecRetTy->isVoidTy())
+      VecRetTy = VectorType::get(VecRetTy, Info.Shape.VF);
 
     FunctionCallee F = M->getOrInsertFunction(
-        VectorName, FunctionType::get(RetTy, CallTypes, false));
+        VectorName, FunctionType::get(VecRetTy, 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());
+    // include a mask when relevant.
+    auto OptVecFTyPos =
+        VFABI::createFunctionType(Info, ScalarFTy, VecRetTy, M.get());
     if (!OptVecFTyPos)
       return false;
 
-    // Ensure that masked Instructions are handled
-    if (isMasked()) {
-      // In case of a masked call, try creating another mock CallInst that is
-      // masked. createFunctionType should be able to handle this.
-      SmallVector<Type *, 8> CallTypesInclMask(CallTypes);
-      SmallVector<Value *, 8> ArgsInclMask(Args);
-      Type *MaskTy = VectorType::get(Type::getInt1Ty(M->getContext()), VF);
-      CallTypesInclMask.push_back(MaskTy);
-      ArgsInclMask.push_back(Constant::getNullValue(MaskTy));
-
-      FunctionCallee FMasked = M->getOrInsertFunction(
-          VectorName + "_Masked",
-          FunctionType::get(RetTy, CallTypesInclMask, false));
-      std::unique_ptr<CallInst> CIMasked(
-          CallInst::Create(FMasked, ArgsInclMask));
-      auto OptVecFTyMaskedPos =
-          VFABI::createFunctionType(Info, CIMasked.get(), M.get());
-      if (!OptVecFTyMaskedPos)
-        return false;
-
-      // Both FunctionTypes should have the same number of parameters.
-      assert(
-          (OptVecFTyPos->first->getNumParams() ==
-           OptVecFTyMaskedPos->first->getNumParams()) &&
-          "createFunctionType should accept masked or non masked Instructions");
-    }
-
     FunctionType *VecFTy = OptVecFTyPos->first;
     // Check that vectorized parameters' size match with VFInfo.
     // Both may include a mask.
@@ -324,7 +297,7 @@ TEST_F(VFABIParserTest, LinearWithCompileTimeNegativeStep) {
   EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
   EXPECT_FALSE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_FALSE(checkFunctionType()); // invalid: all operands are scalar
+  EXPECT_TRUE(checkFunctionType());
   EXPECT_EQ(VF, ElementCount::getFixed(2));
   EXPECT_EQ(Parameters.size(), (unsigned)4);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::OMP_Linear, -1}));
@@ -389,7 +362,7 @@ TEST_F(VFABIParserTest, LinearWithoutCompileTime) {
   EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
   EXPECT_FALSE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_FALSE(checkFunctionType()); // invalid: all operands are scalar
+  EXPECT_TRUE(checkFunctionType());
   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}));
@@ -452,7 +425,7 @@ TEST_F(VFABIParserTest, ParseUniform) {
   EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
   EXPECT_FALSE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_FALSE(checkFunctionType()); // invalid: all operands are scalar
+  EXPECT_TRUE(checkFunctionType());
   EXPECT_EQ(VF, ElementCount::getFixed(2));
   EXPECT_EQ(Parameters.size(), (unsigned)1);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::OMP_Uniform, 0}));

>From 83dad82d71def6de4d0574b0355b6d12bb38f2ac Mon Sep 17 00:00:00 2001
From: Paschalis Mpeis <Paschalis.Mpeis at arm.com>
Date: Wed, 13 Dec 2023 14:15:18 +0000
Subject: [PATCH 4/7] createFunctionType requires only VFInfo and ScalarFTy

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.
---
 llvm/include/llvm/Analysis/VectorUtils.h         | 11 ++++++-----
 llvm/lib/Analysis/VectorUtils.cpp                | 16 ++++++++++------
 .../unittests/Analysis/VectorFunctionABITest.cpp |  7 +++----
 3 files changed, 19 insertions(+), 15 deletions(-)

diff --git a/llvm/include/llvm/Analysis/VectorUtils.h b/llvm/include/llvm/Analysis/VectorUtils.h
index 6b3a001f7c6070..fdb74a2431d138 100644
--- a/llvm/include/llvm/Analysis/VectorUtils.h
+++ b/llvm/include/llvm/Analysis/VectorUtils.h
@@ -196,11 +196,12 @@ static constexpr char const *MappingsAttrName = "vector-function-abi-variant";
 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.
-std::optional<std::pair<FunctionType *, int>>
-createFunctionType(const VFInfo &Info, const FunctionType *ScalarFTy,
-                   Type *VecRetTy, const Module *M);
+/// Returns a vectorized FunctionType that was previously found in
+/// TargetLibraryInfo. It uses \p ScalarFTy for the types, and \p Info to get
+/// the vectorization factor and whether a particular parameter is indeed a
+/// vector, since some of them may be scalars.
+std::optional<FunctionType *> createFunctionType(const VFInfo &Info,
+                                                 const FunctionType *ScalarFTy);
 } // end namespace VFABI
 
 /// The Vector Function Database.
diff --git a/llvm/lib/Analysis/VectorUtils.cpp b/llvm/lib/Analysis/VectorUtils.cpp
index 19529e0f012a30..9a8de7974ba921 100644
--- a/llvm/lib/Analysis/VectorUtils.cpp
+++ b/llvm/lib/Analysis/VectorUtils.cpp
@@ -21,6 +21,7 @@
 #include "llvm/Analysis/TargetTransformInfo.h"
 #include "llvm/Analysis/ValueTracking.h"
 #include "llvm/IR/Constants.h"
+#include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/PatternMatch.h"
 #include "llvm/IR/Value.h"
@@ -1479,9 +1480,8 @@ void VFABI::getVectorVariantNames(
   }
 }
 
-std::optional<std::pair<FunctionType *, int>>
-VFABI::createFunctionType(const VFInfo &Info, const FunctionType *ScalarFTy,
-                          Type *VecRetTy, const Module *M) {
+std::optional<FunctionType *>
+VFABI::createFunctionType(const VFInfo &Info, const FunctionType *ScalarFTy) {
   ElementCount VF = Info.Shape.VF;
   // Create vector parameter types
   SmallVector<Type *, 8> VecTypes;
@@ -1500,11 +1500,15 @@ VFABI::createFunctionType(const VFInfo &Info, const FunctionType *ScalarFTy,
       return std::nullopt;
 
     MaskPos = OptMaskPos.value();
-    VectorType *MaskTy = VectorType::get(Type::getInt1Ty(M->getContext()), VF);
+    VectorType *MaskTy =
+        VectorType::get(Type::getInt1Ty(ScalarFTy->getContext()), VF);
     VecTypes.insert(VecTypes.begin() + MaskPos, MaskTy);
   }
-  FunctionType *VecFTy = FunctionType::get(VecRetTy, VecTypes, false);
-  return std::make_pair(VecFTy, MaskPos);
+  auto *RetTy = ScalarFTy->getReturnType();
+  if (!RetTy->isVoidTy())
+    RetTy = VectorType::get(ScalarFTy->getReturnType(), VF);
+  FunctionType *VecFTy = FunctionType::get(RetTy, VecTypes, false);
+  return VecFTy;
 }
 
 bool VFShape::hasValidParameterList() const {
diff --git a/llvm/unittests/Analysis/VectorFunctionABITest.cpp b/llvm/unittests/Analysis/VectorFunctionABITest.cpp
index e02a3b1c03c1f5..e94a79c1714e67 100644
--- a/llvm/unittests/Analysis/VectorFunctionABITest.cpp
+++ b/llvm/unittests/Analysis/VectorFunctionABITest.cpp
@@ -126,12 +126,11 @@ class VFABIParserTest : public ::testing::Test {
 
     // Use VFInfo and the mock CallInst to create a FunctionType that will
     // include a mask when relevant.
-    auto OptVecFTyPos =
-        VFABI::createFunctionType(Info, ScalarFTy, VecRetTy, M.get());
-    if (!OptVecFTyPos)
+    auto OptVecFTy = VFABI::createFunctionType(Info, ScalarFTy);
+    if (!OptVecFTy)
       return false;
 
-    FunctionType *VecFTy = OptVecFTyPos->first;
+    FunctionType *VecFTy = *OptVecFTy;
     // Check that vectorized parameters' size match with VFInfo.
     // Both may include a mask.
     if ((VecFTy->getNumParams() != Info.Shape.Parameters.size()))

>From af468f3bcad2ae821cc9658c8771f0437f56730f Mon Sep 17 00:00:00 2001
From: Paschalis Mpeis <Paschalis.Mpeis at arm.com>
Date: Thu, 14 Dec 2023 08:47:06 +0000
Subject: [PATCH 5/7] Cleanup: addressing review.

---
 llvm/include/llvm/Analysis/VectorUtils.h        |  4 ++--
 llvm/lib/Analysis/VectorUtils.cpp               | 17 ++++++-----------
 .../Analysis/VectorFunctionABITest.cpp          |  5 ++---
 3 files changed, 10 insertions(+), 16 deletions(-)

diff --git a/llvm/include/llvm/Analysis/VectorUtils.h b/llvm/include/llvm/Analysis/VectorUtils.h
index fdb74a2431d138..ccf4a292daeb82 100644
--- a/llvm/include/llvm/Analysis/VectorUtils.h
+++ b/llvm/include/llvm/Analysis/VectorUtils.h
@@ -200,8 +200,8 @@ void getVectorVariantNames(const CallInst &CI,
 /// TargetLibraryInfo. It uses \p ScalarFTy for the types, and \p Info to get
 /// the vectorization factor and whether a particular parameter is indeed a
 /// vector, since some of them may be scalars.
-std::optional<FunctionType *> createFunctionType(const VFInfo &Info,
-                                                 const FunctionType *ScalarFTy);
+FunctionType *createFunctionType(const VFInfo &Info,
+                                 const FunctionType *ScalarFTy);
 } // end namespace VFABI
 
 /// The Vector Function Database.
diff --git a/llvm/lib/Analysis/VectorUtils.cpp b/llvm/lib/Analysis/VectorUtils.cpp
index 9a8de7974ba921..c64ca1d845626b 100644
--- a/llvm/lib/Analysis/VectorUtils.cpp
+++ b/llvm/lib/Analysis/VectorUtils.cpp
@@ -1480,8 +1480,8 @@ void VFABI::getVectorVariantNames(
   }
 }
 
-std::optional<FunctionType *>
-VFABI::createFunctionType(const VFInfo &Info, const FunctionType *ScalarFTy) {
+FunctionType *VFABI::createFunctionType(const VFInfo &Info,
+                                        const FunctionType *ScalarFTy) {
   ElementCount VF = Info.Shape.VF;
   // Create vector parameter types
   SmallVector<Type *, 8> VecTypes;
@@ -1493,22 +1493,17 @@ VFABI::createFunctionType(const VFInfo &Info, const FunctionType *ScalarFTy) {
   }
 
   // Get mask's position mask and append one if not present in the Instruction.
-  int MaskPos = -1;
-  if (Info.isMasked()) {
-    auto OptMaskPos = Info.getParamIndexForOptionalMask();
+  if (auto OptMaskPos = Info.getParamIndexForOptionalMask()) {
     if (!OptMaskPos)
-      return std::nullopt;
-
-    MaskPos = OptMaskPos.value();
+      return nullptr;
     VectorType *MaskTy =
         VectorType::get(Type::getInt1Ty(ScalarFTy->getContext()), VF);
-    VecTypes.insert(VecTypes.begin() + MaskPos, MaskTy);
+    VecTypes.insert(VecTypes.begin() + OptMaskPos.value(), MaskTy);
   }
   auto *RetTy = ScalarFTy->getReturnType();
   if (!RetTy->isVoidTy())
     RetTy = VectorType::get(ScalarFTy->getReturnType(), VF);
-  FunctionType *VecFTy = FunctionType::get(RetTy, VecTypes, false);
-  return VecFTy;
+  return FunctionType::get(RetTy, VecTypes, false);
 }
 
 bool VFShape::hasValidParameterList() const {
diff --git a/llvm/unittests/Analysis/VectorFunctionABITest.cpp b/llvm/unittests/Analysis/VectorFunctionABITest.cpp
index e94a79c1714e67..5307493b6c5b3e 100644
--- a/llvm/unittests/Analysis/VectorFunctionABITest.cpp
+++ b/llvm/unittests/Analysis/VectorFunctionABITest.cpp
@@ -126,11 +126,10 @@ class VFABIParserTest : public ::testing::Test {
 
     // Use VFInfo and the mock CallInst to create a FunctionType that will
     // include a mask when relevant.
-    auto OptVecFTy = VFABI::createFunctionType(Info, ScalarFTy);
-    if (!OptVecFTy)
+    FunctionType *VecFTy = VFABI::createFunctionType(Info, ScalarFTy);
+    if (!VecFTy)
       return false;
 
-    FunctionType *VecFTy = *OptVecFTy;
     // Check that vectorized parameters' size match with VFInfo.
     // Both may include a mask.
     if ((VecFTy->getNumParams() != Info.Shape.Parameters.size()))

>From b4c4a53873ea1052cc4566599b9ec2896c1734ac Mon Sep 17 00:00:00 2001
From: Paschalis Mpeis <Paschalis.Mpeis at arm.com>
Date: Mon, 18 Dec 2023 11:42:41 +0000
Subject: [PATCH 6/7] Improve testing for createFunctionType.

Refactored 'createFunctionType'
---
 llvm/include/llvm/Analysis/VectorUtils.h      |   6 +-
 llvm/lib/Analysis/VectorUtils.cpp             |  28 +--
 .../Analysis/VectorFunctionABITest.cpp        | 232 ++++++++++--------
 3 files changed, 151 insertions(+), 115 deletions(-)

diff --git a/llvm/include/llvm/Analysis/VectorUtils.h b/llvm/include/llvm/Analysis/VectorUtils.h
index ccf4a292daeb82..09566f9998d046 100644
--- a/llvm/include/llvm/Analysis/VectorUtils.h
+++ b/llvm/include/llvm/Analysis/VectorUtils.h
@@ -196,10 +196,8 @@ static constexpr char const *MappingsAttrName = "vector-function-abi-variant";
 void getVectorVariantNames(const CallInst &CI,
                            SmallVectorImpl<std::string> &VariantMappings);
 
-/// Returns a vectorized FunctionType that was previously found in
-/// TargetLibraryInfo. It uses \p ScalarFTy for the types, and \p Info to get
-/// the vectorization factor and whether a particular parameter is indeed a
-/// vector, since some of them may be scalars.
+/// Constructs a FunctionType by applying vector function information to the
+/// type of a matching scalar function.
 FunctionType *createFunctionType(const VFInfo &Info,
                                  const FunctionType *ScalarFTy);
 } // end namespace VFABI
diff --git a/llvm/lib/Analysis/VectorUtils.cpp b/llvm/lib/Analysis/VectorUtils.cpp
index c64ca1d845626b..36650eb0531a7c 100644
--- a/llvm/lib/Analysis/VectorUtils.cpp
+++ b/llvm/lib/Analysis/VectorUtils.cpp
@@ -26,7 +26,6 @@
 #include "llvm/IR/PatternMatch.h"
 #include "llvm/IR/Value.h"
 #include "llvm/Support/CommandLine.h"
-#include <optional>
 
 #define DEBUG_TYPE "vectorutils"
 
@@ -1482,27 +1481,26 @@ void VFABI::getVectorVariantNames(
 
 FunctionType *VFABI::createFunctionType(const VFInfo &Info,
                                         const FunctionType *ScalarFTy) {
-  ElementCount VF = Info.Shape.VF;
   // Create vector parameter types
   SmallVector<Type *, 8> VecTypes;
-  for (auto [STy, VFParam] : zip(ScalarFTy->params(), Info.Shape.Parameters)) {
+  ElementCount VF = Info.Shape.VF;
+  for (auto [Idx, VFParam] : enumerate(Info.Shape.Parameters)) {
+    if (VFParam.ParamKind == VFParamKind::GlobalPredicate) {
+      VectorType *MaskTy =
+          VectorType::get(Type::getInt1Ty(ScalarFTy->getContext()), VF);
+      VecTypes.push_back(MaskTy);
+      continue;
+    }
+
+    Type *OperandTy = ScalarFTy->getParamType(Idx);
     if (VFParam.ParamKind == VFParamKind::Vector)
-      VecTypes.push_back(VectorType::get(STy, VF));
-    else
-      VecTypes.push_back(STy);
+      OperandTy = VectorType::get(OperandTy, VF);
+    VecTypes.push_back(OperandTy);
   }
 
-  // Get mask's position mask and append one if not present in the Instruction.
-  if (auto OptMaskPos = Info.getParamIndexForOptionalMask()) {
-    if (!OptMaskPos)
-      return nullptr;
-    VectorType *MaskTy =
-        VectorType::get(Type::getInt1Ty(ScalarFTy->getContext()), VF);
-    VecTypes.insert(VecTypes.begin() + OptMaskPos.value(), MaskTy);
-  }
   auto *RetTy = ScalarFTy->getReturnType();
   if (!RetTy->isVoidTy())
-    RetTy = VectorType::get(ScalarFTy->getReturnType(), VF);
+    RetTy = VectorType::get(RetTy, VF);
   return FunctionType::get(RetTy, VecTypes, false);
 }
 
diff --git a/llvm/unittests/Analysis/VectorFunctionABITest.cpp b/llvm/unittests/Analysis/VectorFunctionABITest.cpp
index 5307493b6c5b3e..9ab6d5d1e38c8c 100644
--- a/llvm/unittests/Analysis/VectorFunctionABITest.cpp
+++ b/llvm/unittests/Analysis/VectorFunctionABITest.cpp
@@ -16,6 +16,9 @@
 using namespace llvm;
 
 namespace {
+
+static LLVMContext Ctx;
+
 /// Perform tests against VFABI Rules. `invokeParser` creates a VFInfo object
 /// and a scalar FunctionType, which are used by tests to check that:
 /// 1. The scalar and vector names are correct.
@@ -46,7 +49,6 @@ class VFABIParserTest : public ::testing::Test {
   }
 
   // Data needed to load the optional IR passed to invokeParser
-  LLVMContext Ctx;
   SMDiagnostic Err;
   std::unique_ptr<Module> M;
   FunctionType *ScalarFTy = nullptr;
@@ -93,77 +95,36 @@ class VFABIParserTest : public ::testing::Test {
     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() {
-    // For scalable ISAs, the created vector FunctionType might have a mask
-    // parameter Type, according to VFABI. Regardless, this input CallInst,
-    // despite being a vectorized call, it will not have a masked 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 *VecRetTy = ScalarFTy->getReturnType();
-    if (!VecRetTy->isVoidTy())
-      VecRetTy = VectorType::get(VecRetTy, Info.Shape.VF);
-
-    FunctionCallee F = M->getOrInsertFunction(
-        VectorName, FunctionType::get(VecRetTy, 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 when relevant.
-    FunctionType *VecFTy = VFABI::createFunctionType(Info, ScalarFTy);
-    if (!VecFTy)
-      return false;
-
-    // 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;
+  FunctionType *getFunctionType() {
+    return VFABI::createFunctionType(Info, ScalarFTy);
   }
 };
 } // unnamed namespace
 
+// Function Types commonly used in tests
+FunctionType *FTyMaskVLen2_i32 = FunctionType::get(
+    Type::getVoidTy(Ctx),
+    {
+        VectorType::get(Type::getInt32Ty(Ctx), ElementCount::getFixed(2)),
+        VectorType::get(Type::getInt1Ty(Ctx), ElementCount::getFixed(2)),
+    },
+    false);
+
+FunctionType *FTyNoMaskVLen2_i32 = FunctionType::get(
+    Type::getVoidTy(Ctx),
+    {
+        VectorType::get(Type::getInt32Ty(Ctx), ElementCount::getFixed(2)),
+    },
+    false);
+
+FunctionType *FTyMaskedVLA_i32 = FunctionType::get(
+    Type::getVoidTy(Ctx),
+    {
+        VectorType::get(Type::getInt32Ty(Ctx), ElementCount::getScalable(4)),
+        VectorType::get(Type::getInt1Ty(Ctx), ElementCount::getScalable(4)),
+    },
+    false);
+
 // This test makes sure that the demangling method succeeds only on
 // valid values of the string.
 TEST_F(VFABIParserTest, OnlyValidNames) {
@@ -201,7 +162,13 @@ TEST_F(VFABIParserTest, ParamListParsing) {
   EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
   EXPECT_EQ(false, isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  FunctionType *FTy = FunctionType::get(
+      Type::getVoidTy(Ctx),
+      {VectorType::get(Type::getInt32Ty(Ctx), ElementCount::getFixed(2)),
+       Type::getInt32Ty(Ctx), Type::getInt32Ty(Ctx),
+       Type::getInt32Ty(Ctx)->getPointerTo(), Type::getInt32Ty(Ctx)},
+      false);
+  EXPECT_EQ(getFunctionType(), FTy);
   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}));
@@ -217,7 +184,7 @@ TEST_F(VFABIParserTest, ScalarNameAndVectorName_01) {
   EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
   EXPECT_EQ(true, isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  EXPECT_EQ(getFunctionType(), FTyMaskVLen2_i32);
   EXPECT_EQ(ScalarName, "foo");
   EXPECT_EQ(VectorName, "vector_foo");
 }
@@ -227,7 +194,7 @@ TEST_F(VFABIParserTest, ScalarNameAndVectorName_02) {
   EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
   EXPECT_EQ(true, isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  EXPECT_EQ(getFunctionType(), FTyMaskVLen2_i32);
   EXPECT_EQ(ScalarName, "foo");
   EXPECT_EQ(VectorName, "vector_foo");
 }
@@ -238,7 +205,7 @@ TEST_F(VFABIParserTest, ScalarNameAndVectorName_03) {
   EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
   EXPECT_EQ(true, isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  EXPECT_EQ(getFunctionType(), FTyMaskVLen2_i32);
   EXPECT_EQ(ScalarName, "__foo_bar_abc");
   EXPECT_EQ(VectorName, "fooBarAbcVec");
 }
@@ -260,7 +227,21 @@ TEST_F(VFABIParserTest, Parse) {
   EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
   EXPECT_FALSE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  FunctionType *FTy = FunctionType::get(
+      Type::getVoidTy(Ctx),
+      {
+          VectorType::get(Type::getInt32Ty(Ctx), ElementCount::getFixed(2)),
+          Type::getInt32Ty(Ctx),
+          Type::getInt32Ty(Ctx),
+          Type::getInt32Ty(Ctx),
+          Type::getInt32Ty(Ctx)->getPointerTo(),
+          Type::getInt32Ty(Ctx),
+          Type::getInt32Ty(Ctx),
+          Type::getInt32Ty(Ctx),
+          Type::getInt32Ty(Ctx)->getPointerTo(),
+      },
+      false);
+  EXPECT_EQ(getFunctionType(), FTy);
   EXPECT_EQ(VF, ElementCount::getFixed(2));
   EXPECT_EQ(Parameters.size(), (unsigned)9);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector, 0}));
@@ -281,7 +262,7 @@ TEST_F(VFABIParserTest, ParseVectorName) {
   EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
   EXPECT_FALSE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  EXPECT_EQ(getFunctionType(), FTyNoMaskVLen2_i32);
   EXPECT_EQ(VF, ElementCount::getFixed(2));
   EXPECT_EQ(Parameters.size(), (unsigned)1);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector, 0}));
@@ -295,7 +276,12 @@ TEST_F(VFABIParserTest, LinearWithCompileTimeNegativeStep) {
   EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
   EXPECT_FALSE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  FunctionType *FTy = FunctionType::get(
+      Type::getVoidTy(Ctx),
+      {Type::getInt32Ty(Ctx), Type::getInt32Ty(Ctx), Type::getInt32Ty(Ctx),
+       Type::getInt32Ty(Ctx)->getPointerTo()},
+      false);
+  EXPECT_EQ(getFunctionType(), FTy);
   EXPECT_EQ(VF, ElementCount::getFixed(2));
   EXPECT_EQ(Parameters.size(), (unsigned)4);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::OMP_Linear, -1}));
@@ -311,7 +297,7 @@ TEST_F(VFABIParserTest, ParseScalableSVE) {
   EXPECT_EQ(ISA, VFISAKind::SVE);
   EXPECT_TRUE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  EXPECT_EQ(getFunctionType(), FTyMaskedVLA_i32);
   EXPECT_EQ(VF, ElementCount::getScalable(4));
   EXPECT_EQ(Parameters.size(), (unsigned)2);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
@@ -325,7 +311,7 @@ TEST_F(VFABIParserTest, ParseFixedWidthSVE) {
   EXPECT_EQ(ISA, VFISAKind::SVE);
   EXPECT_TRUE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  EXPECT_EQ(getFunctionType(), FTyMaskVLen2_i32);
   EXPECT_EQ(VF, ElementCount::getFixed(2));
   EXPECT_EQ(Parameters.size(), (unsigned)2);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
@@ -360,7 +346,14 @@ TEST_F(VFABIParserTest, LinearWithoutCompileTime) {
   EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
   EXPECT_FALSE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  FunctionType *FTy = FunctionType::get(
+      Type::getVoidTy(Ctx),
+      {Type::getInt32Ty(Ctx), Type::getInt32Ty(Ctx),
+       Type::getInt32Ty(Ctx)->getPointerTo(), Type::getInt32Ty(Ctx),
+       Type::getInt32Ty(Ctx), Type::getInt32Ty(Ctx),
+       Type::getInt32Ty(Ctx)->getPointerTo(), Type::getInt32Ty(Ctx)},
+      false);
+  EXPECT_EQ(getFunctionType(), FTy);
   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}));
@@ -380,7 +373,7 @@ TEST_F(VFABIParserTest, LLVM_ISA) {
   EXPECT_EQ(ISA, VFISAKind::LLVM);
   EXPECT_FALSE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  EXPECT_EQ(getFunctionType(), FTyNoMaskVLen2_i32);
   EXPECT_EQ(Parameters.size(), (unsigned)1);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
   EXPECT_EQ(ScalarName, "foo");
@@ -423,7 +416,9 @@ TEST_F(VFABIParserTest, ParseUniform) {
   EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
   EXPECT_FALSE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  FunctionType *FTy =
+      FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt32Ty(Ctx)}, false);
+  EXPECT_EQ(getFunctionType(), FTy);
   EXPECT_EQ(VF, ElementCount::getFixed(2));
   EXPECT_EQ(Parameters.size(), (unsigned)1);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::OMP_Uniform, 0}));
@@ -439,6 +434,15 @@ TEST_F(VFABIParserTest, ISAIndependentMangling) {
   // independent on the <isa> token.
   const StringRef IRTy =
       "void(i32, i32, i32, i32, ptr, i32, i32, i32, i32, i32)";
+  FunctionType *FTy = FunctionType::get(
+      Type::getVoidTy(Ctx),
+      {VectorType::get(Type::getInt32Ty(Ctx), ElementCount::getFixed(2)),
+       Type::getInt32Ty(Ctx), Type::getInt32Ty(Ctx), Type::getInt32Ty(Ctx),
+       Type::getInt32Ty(Ctx)->getPointerTo(), Type::getInt32Ty(Ctx),
+       Type::getInt32Ty(Ctx), Type::getInt32Ty(Ctx), Type::getInt32Ty(Ctx),
+       Type::getInt32Ty(Ctx)},
+      false);
+
   const SmallVector<VFParameter, 8> ExpectedParams = {
       VFParameter({0, VFParamKind::Vector, 0}),
       VFParameter({1, VFParamKind::OMP_LinearPos, 2}),
@@ -457,7 +461,7 @@ TEST_F(VFABIParserTest, ISAIndependentMangling) {
     EXPECT_EQ(VF, ElementCount::getFixed(2));                                  \
     EXPECT_FALSE(isMasked());                                                  \
     EXPECT_TRUE(matchParametersNum());                                         \
-    EXPECT_TRUE(checkFunctionType());                                          \
+    EXPECT_EQ(getFunctionType(), FTy);                                         \
     EXPECT_EQ(Parameters.size(), (unsigned)10);                                \
     EXPECT_EQ(Parameters, ExpectedParams);                                     \
     EXPECT_EQ(ScalarName, "foo");                                              \
@@ -533,7 +537,7 @@ TEST_F(VFABIParserTest, ParseMaskingNEON) {
   EXPECT_EQ(ISA, VFISAKind::AdvancedSIMD);
   EXPECT_TRUE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  EXPECT_EQ(getFunctionType(), FTyMaskVLen2_i32);
   EXPECT_EQ(VF, ElementCount::getFixed(2));
   EXPECT_EQ(Parameters.size(), (unsigned)2);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
@@ -547,7 +551,7 @@ TEST_F(VFABIParserTest, ParseMaskingSVE) {
   EXPECT_EQ(ISA, VFISAKind::SVE);
   EXPECT_TRUE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  EXPECT_EQ(getFunctionType(), FTyMaskVLen2_i32);
   EXPECT_EQ(VF, ElementCount::getFixed(2));
   EXPECT_EQ(Parameters.size(), (unsigned)2);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
@@ -561,7 +565,7 @@ TEST_F(VFABIParserTest, ParseMaskingSSE) {
   EXPECT_EQ(ISA, VFISAKind::SSE);
   EXPECT_TRUE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  EXPECT_EQ(getFunctionType(), FTyMaskVLen2_i32);
   EXPECT_EQ(VF, ElementCount::getFixed(2));
   EXPECT_EQ(Parameters.size(), (unsigned)2);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
@@ -575,7 +579,7 @@ TEST_F(VFABIParserTest, ParseMaskingAVX) {
   EXPECT_EQ(ISA, VFISAKind::AVX);
   EXPECT_TRUE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  EXPECT_EQ(getFunctionType(), FTyMaskVLen2_i32);
   EXPECT_EQ(VF, ElementCount::getFixed(2));
   EXPECT_EQ(Parameters.size(), (unsigned)2);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
@@ -589,7 +593,7 @@ TEST_F(VFABIParserTest, ParseMaskingAVX2) {
   EXPECT_EQ(ISA, VFISAKind::AVX2);
   EXPECT_TRUE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  EXPECT_EQ(getFunctionType(), FTyMaskVLen2_i32);
   EXPECT_EQ(VF, ElementCount::getFixed(2));
   EXPECT_EQ(Parameters.size(), (unsigned)2);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
@@ -603,7 +607,7 @@ TEST_F(VFABIParserTest, ParseMaskingAVX512) {
   EXPECT_EQ(ISA, VFISAKind::AVX512);
   EXPECT_TRUE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  EXPECT_EQ(getFunctionType(), FTyMaskVLen2_i32);
   EXPECT_EQ(VF, ElementCount::getFixed(2));
   EXPECT_EQ(Parameters.size(), (unsigned)2);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
@@ -617,7 +621,7 @@ TEST_F(VFABIParserTest, ParseMaskingLLVM) {
   EXPECT_EQ(ISA, VFISAKind::LLVM);
   EXPECT_TRUE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  EXPECT_EQ(getFunctionType(), FTyMaskVLen2_i32);
   EXPECT_EQ(VF, ElementCount::getFixed(2));
   EXPECT_EQ(Parameters.size(), (unsigned)2);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
@@ -636,20 +640,27 @@ TEST_F(VFABIParserTest, LLVM_InternalISA) {
   EXPECT_EQ(ISA, VFISAKind::LLVM);
   EXPECT_FALSE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  EXPECT_EQ(getFunctionType(), FTyNoMaskVLen2_i32);
   EXPECT_EQ(Parameters.size(), (unsigned)1);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
   EXPECT_EQ(ScalarName, "foo");
   EXPECT_EQ(VectorName, "vector_foo");
 }
 
-TEST_F(VFABIParserTest, IntrinsicsInLLVMIsa) {
+TEST_F(VFABIParserTest, LLVM_Intrinsics) {
   EXPECT_TRUE(invokeParser("_ZGV_LLVM_N4vv_llvm.pow.f32(__svml_powf4)",
                            "void(float, float)"));
   EXPECT_EQ(ISA, VFISAKind::LLVM);
   EXPECT_FALSE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  FunctionType *FTy = FunctionType::get(
+      Type::getVoidTy(Ctx),
+      {
+          VectorType::get(Type::getFloatTy(Ctx), ElementCount::getFixed(4)),
+          VectorType::get(Type::getFloatTy(Ctx), ElementCount::getFixed(4)),
+      },
+      false);
+  EXPECT_EQ(getFunctionType(), FTy);
   EXPECT_EQ(VF, ElementCount::getFixed(4));
   EXPECT_EQ(Parameters.size(), (unsigned)2);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
@@ -665,7 +676,7 @@ TEST_F(VFABIParserTest, ParseScalableRequiresDeclaration) {
   EXPECT_EQ(ISA, VFISAKind::SVE);
   EXPECT_TRUE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  EXPECT_EQ(getFunctionType(), FTyMaskedVLA_i32);
   EXPECT_EQ(Parameters.size(), (unsigned)2);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
   EXPECT_EQ(Parameters[1], VFParameter({1, VFParamKind::GlobalPredicate}));
@@ -685,7 +696,12 @@ TEST_F(VFABIParserTest, ParseScalableMaskingSVE) {
   EXPECT_EQ(ISA, VFISAKind::SVE);
   EXPECT_TRUE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  FunctionType *FTy = FunctionType::get(
+      VectorType::get(Type::getInt32Ty(Ctx), ElementCount::getScalable(4)),
+      {VectorType::get(Type::getInt32Ty(Ctx), ElementCount::getScalable(4)),
+       VectorType::get(Type::getInt1Ty(Ctx), ElementCount::getScalable(4))},
+      false);
+  EXPECT_EQ(getFunctionType(), FTy);
   EXPECT_EQ(VF, ElementCount::getScalable(4));
   EXPECT_EQ(Parameters.size(), (unsigned)2);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
@@ -700,7 +716,16 @@ TEST_F(VFABIParserTest, ParseScalableMaskingSVESincos) {
   EXPECT_EQ(ISA, VFISAKind::SVE);
   EXPECT_TRUE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  FunctionType *FTy = FunctionType::get(
+      Type::getVoidTy(Ctx),
+      {
+          VectorType::get(Type::getDoubleTy(Ctx), ElementCount::getScalable(2)),
+          Type::getInt32Ty(Ctx)->getPointerTo(),
+          Type::getInt32Ty(Ctx)->getPointerTo(),
+          VectorType::get(Type::getInt1Ty(Ctx), ElementCount::getScalable(2)),
+      },
+      false);
+  EXPECT_EQ(getFunctionType(), FTy);
   EXPECT_EQ(VF, ElementCount::getScalable(2));
   EXPECT_EQ(Parameters.size(), (unsigned)4);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
@@ -718,7 +743,15 @@ TEST_F(VFABIParserTest, ParseWiderReturnTypeSVE) {
   EXPECT_EQ(ISA, VFISAKind::SVE);
   EXPECT_TRUE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  FunctionType *FTy = FunctionType::get(
+      VectorType::get(Type::getInt64Ty(Ctx), ElementCount::getScalable(2)),
+      {
+          VectorType::get(Type::getInt32Ty(Ctx), ElementCount::getScalable(2)),
+          VectorType::get(Type::getInt32Ty(Ctx), ElementCount::getScalable(2)),
+          VectorType::get(Type::getInt1Ty(Ctx), ElementCount::getScalable(2)),
+      },
+      false);
+  EXPECT_EQ(getFunctionType(), FTy);
   EXPECT_EQ(Parameters.size(), (unsigned)3);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
   EXPECT_EQ(Parameters[1], VFParameter({1, VFParamKind::Vector}));
@@ -734,7 +767,14 @@ TEST_F(VFABIParserTest, ParseVoidReturnTypeSVE) {
   EXPECT_EQ(ISA, VFISAKind::SVE);
   EXPECT_TRUE(isMasked());
   EXPECT_TRUE(matchParametersNum());
-  EXPECT_TRUE(checkFunctionType());
+  FunctionType *FTy = FunctionType::get(
+      Type::getVoidTy(Ctx),
+      {
+          VectorType::get(Type::getInt16Ty(Ctx), ElementCount::getScalable(8)),
+          VectorType::get(Type::getInt1Ty(Ctx), ElementCount::getScalable(8)),
+      },
+      false);
+  EXPECT_EQ(getFunctionType(), FTy);
   EXPECT_EQ(Parameters.size(), (unsigned)2);
   EXPECT_EQ(Parameters[0], VFParameter({0, VFParamKind::Vector}));
   EXPECT_EQ(Parameters[1], VFParameter({1, VFParamKind::GlobalPredicate}));

>From 0fa66728731efdc70b2488e19bc77a79d844facd Mon Sep 17 00:00:00 2001
From: Paschalis Mpeis <Paschalis.Mpeis at arm.com>
Date: Mon, 18 Dec 2023 13:49:53 +0000
Subject: [PATCH 7/7] Improve handling of Vectors in 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.
---
 llvm/lib/Analysis/VectorUtils.cpp                 | 5 +++--
 llvm/unittests/Analysis/VectorFunctionABITest.cpp | 5 ++++-
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Analysis/VectorUtils.cpp b/llvm/lib/Analysis/VectorUtils.cpp
index 36650eb0531a7c..f90fca9d937fc3 100644
--- a/llvm/lib/Analysis/VectorUtils.cpp
+++ b/llvm/lib/Analysis/VectorUtils.cpp
@@ -1484,7 +1484,8 @@ FunctionType *VFABI::createFunctionType(const VFInfo &Info,
   // Create vector parameter types
   SmallVector<Type *, 8> VecTypes;
   ElementCount VF = Info.Shape.VF;
-  for (auto [Idx, VFParam] : enumerate(Info.Shape.Parameters)) {
+  int ScalarParamIndex = 0;
+  for (auto VFParam : Info.Shape.Parameters) {
     if (VFParam.ParamKind == VFParamKind::GlobalPredicate) {
       VectorType *MaskTy =
           VectorType::get(Type::getInt1Ty(ScalarFTy->getContext()), VF);
@@ -1492,7 +1493,7 @@ FunctionType *VFABI::createFunctionType(const VFInfo &Info,
       continue;
     }
 
-    Type *OperandTy = ScalarFTy->getParamType(Idx);
+    Type *OperandTy = ScalarFTy->getParamType(ScalarParamIndex++);
     if (VFParam.ParamKind == VFParamKind::Vector)
       OperandTy = VectorType::get(OperandTy, VF);
     VecTypes.push_back(OperandTy);
diff --git a/llvm/unittests/Analysis/VectorFunctionABITest.cpp b/llvm/unittests/Analysis/VectorFunctionABITest.cpp
index 9ab6d5d1e38c8c..b72b4b3b21d439 100644
--- a/llvm/unittests/Analysis/VectorFunctionABITest.cpp
+++ b/llvm/unittests/Analysis/VectorFunctionABITest.cpp
@@ -9,6 +9,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Analysis/VectorUtils.h"
 #include "llvm/AsmParser/Parser.h"
+#include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/InstIterator.h"
 #include "gtest/gtest.h"
 #include <optional>
@@ -397,7 +398,9 @@ TEST_F(VFABIParserTest, Align) {
   EXPECT_EQ(Parameters[0].Alignment, Align(2));
   EXPECT_EQ(ScalarName, "foo");
   EXPECT_EQ(VectorName, "vector_foo");
-
+  FunctionType *FTy =
+      FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt32Ty(Ctx)}, false);
+  EXPECT_EQ(getFunctionType(), FTy);
   // Missing alignment value.
   EXPECT_FALSE(invokeParser("_ZGVsM2l2a_foo"));
   // Invalid alignment token "x".



More information about the llvm-commits mailing list