[llvm] [VectorTypeUtil] Support struct return types for widen intrinsics (NFC). (PR #165218)
Shih-Po Hung via llvm-commits
llvm-commits at lists.llvm.org
Sat Dec 13 17:15:04 PST 2025
https://github.com/arcbbb updated https://github.com/llvm/llvm-project/pull/165218
>From 4329bf578d784840dbc7e5ab12d822f9bb9522e9 Mon Sep 17 00:00:00 2001
From: ShihPo Hung <shihpo.hung at sifive.com>
Date: Wed, 3 Dec 2025 03:51:02 -0800
Subject: [PATCH 1/2] [VectorTypeUtil] Support struct return types for widen
intrinsics (NFC). #165218
Splitting from #151300, vp_load_ff returns a struct type that cannot be
widened by toVectorizedTy.
This patch adds isVectorIntrinsicWithStructReturnScalarAtField and widen
each struct element type independently.
---
llvm/include/llvm/IR/VectorTypeUtils.h | 15 ++++++++++++---
llvm/lib/Analysis/VectorUtils.cpp | 4 ++++
llvm/lib/IR/VectorTypeUtils.cpp | 16 ++++++++++++++--
llvm/lib/Transforms/Vectorize/LoopVectorize.cpp | 6 +++++-
llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp | 14 ++++++++++++--
llvm/unittests/IR/VectorTypeUtilsTest.cpp | 7 +++++++
6 files changed, 54 insertions(+), 8 deletions(-)
diff --git a/llvm/include/llvm/IR/VectorTypeUtils.h b/llvm/include/llvm/IR/VectorTypeUtils.h
index e3d7fadad6089..3db5c4a2b6576 100644
--- a/llvm/include/llvm/IR/VectorTypeUtils.h
+++ b/llvm/include/llvm/IR/VectorTypeUtils.h
@@ -14,6 +14,11 @@
namespace llvm {
+/// Returns true if \p IID is a vector intrinsic that returns a struct with a
+/// scalar element at index \p EleIdx.
+LLVM_ABI bool isVectorIntrinsicWithStructReturnScalarAtField(unsigned IID,
+ unsigned EleIdx);
+
/// A helper function for converting Scalar types to vector types. If
/// the incoming type is void, we return void. If the EC represents a
/// scalar, we return the scalar type.
@@ -31,7 +36,11 @@ inline Type *toVectorTy(Type *Scalar, unsigned VF) {
/// Note:
/// - If \p EC is scalar, \p StructTy is returned unchanged
/// - Only unpacked literal struct types are supported
-LLVM_ABI Type *toVectorizedStructTy(StructType *StructTy, ElementCount EC);
+/// vector types.
+/// - If IID (Intrinsic ID) is provided, only fields that are vector types
+/// are widened.
+LLVM_ABI Type *toVectorizedStructTy(StructType *StructTy, ElementCount EC,
+ unsigned IID = 0);
/// A helper for converting structs of vector types to structs of scalar types.
/// Note: Only unpacked literal struct types are supported.
@@ -52,9 +61,9 @@ LLVM_ABI bool canVectorizeStructTy(StructType *StructTy);
/// - If the incoming type is void, we return void
/// - If \p EC is scalar, \p Ty is returned unchanged
/// - Only unpacked literal struct types are supported
-inline Type *toVectorizedTy(Type *Ty, ElementCount EC) {
+inline Type *toVectorizedTy(Type *Ty, ElementCount EC, unsigned IID = 0) {
if (StructType *StructTy = dyn_cast<StructType>(Ty))
- return toVectorizedStructTy(StructTy, EC);
+ return toVectorizedStructTy(StructTy, EC, IID);
return toVectorTy(Ty, EC);
}
diff --git a/llvm/lib/Analysis/VectorUtils.cpp b/llvm/lib/Analysis/VectorUtils.cpp
index a3e9b039f9225..85d1516f40c4c 100644
--- a/llvm/lib/Analysis/VectorUtils.cpp
+++ b/llvm/lib/Analysis/VectorUtils.cpp
@@ -224,6 +224,10 @@ bool llvm::isVectorIntrinsicWithStructReturnOverloadAtField(
return TTI->isTargetIntrinsicWithStructReturnOverloadAtField(ID, RetIdx);
switch (ID) {
+ case Intrinsic::modf:
+ case Intrinsic::sincos:
+ case Intrinsic::sincospi:
+ return false;
case Intrinsic::frexp:
return RetIdx == 0 || RetIdx == 1;
default:
diff --git a/llvm/lib/IR/VectorTypeUtils.cpp b/llvm/lib/IR/VectorTypeUtils.cpp
index 62e39aab90079..5b0b62dac1473 100644
--- a/llvm/lib/IR/VectorTypeUtils.cpp
+++ b/llvm/lib/IR/VectorTypeUtils.cpp
@@ -8,12 +8,21 @@
#include "llvm/IR/VectorTypeUtils.h"
#include "llvm/ADT/SmallVectorExtras.h"
+#include "llvm/IR/Intrinsics.h"
using namespace llvm;
+bool llvm::isVectorIntrinsicWithStructReturnScalarAtField(unsigned IID,
+ unsigned EleIdx) {
+ if (IID == Intrinsic::vp_load_ff)
+ return EleIdx == 1;
+ return false;
+}
+
/// A helper for converting structs of scalar types to structs of vector types.
/// Note: Only unpacked literal struct types are supported.
-Type *llvm::toVectorizedStructTy(StructType *StructTy, ElementCount EC) {
+Type *llvm::toVectorizedStructTy(StructType *StructTy, ElementCount EC,
+ unsigned IID) {
if (EC.isScalar())
return StructTy;
assert(isUnpackedStructLiteral(StructTy) &&
@@ -22,7 +31,10 @@ Type *llvm::toVectorizedStructTy(StructType *StructTy, ElementCount EC) {
"expected all element types to be valid vector element types");
return StructType::get(
StructTy->getContext(),
- map_to_vector(StructTy->elements(), [&](Type *ElTy) -> Type * {
+ map_to_vector(enumerate(StructTy->elements()), [&](auto It) -> Type * {
+ Type *ElTy = It.value();
+ if (isVectorIntrinsicWithStructReturnScalarAtField(IID, It.index()))
+ return ElTy;
return VectorType::get(ElTy, EC);
}));
}
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 62b68232925d9..b954d3f5ebe44 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -4139,7 +4139,11 @@ static bool willGenerateVectors(VPlan &Plan, ElementCount VF,
Type *ScalarTy = TypeInfo.inferScalarType(ToCheck);
if (!Visited.insert({ScalarTy}).second)
continue;
- Type *WideTy = toVectorizedTy(ScalarTy, VF);
+ unsigned IID = 0;
+ if (auto *WI = dyn_cast<VPWidenIntrinsicRecipe>(&R))
+ WI->getVectorIntrinsicID();
+ Type *WideTy = toVectorizedTy(ScalarTy, VF, IID);
+
if (any_of(getContainedTypes(WideTy), WillGenerateTargetVectors))
return true;
}
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index 0baf7172e4443..a40df5084649f 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -1679,7 +1679,16 @@ void VPWidenIntrinsicRecipe::execute(VPTransformState &State) {
SmallVector<Type *, 2> TysForDecl;
// Add return type if intrinsic is overloaded on it.
- if (isVectorIntrinsicWithOverloadTypeAtArg(VectorIntrinsicID, -1, State.TTI))
+ if (ResultTy->isStructTy()) {
+ auto *StructTy = cast<StructType>(ResultTy);
+ for (unsigned I = 0, E = StructTy->getNumElements(); I != E; ++I) {
+ if (isVectorIntrinsicWithStructReturnOverloadAtField(VectorIntrinsicID, I,
+ State.TTI))
+ TysForDecl.push_back(
+ toVectorizedTy(StructTy->getStructElementType(I), State.VF));
+ }
+ } else if (isVectorIntrinsicWithOverloadTypeAtArg(VectorIntrinsicID, -1,
+ State.TTI))
TysForDecl.push_back(VectorType::get(getResultType(), State.VF));
SmallVector<Value *, 4> Args;
for (const auto &I : enumerate(operands())) {
@@ -1744,7 +1753,8 @@ static InstructionCost getCostForIntrinsics(Intrinsic::ID ID,
}
Type *ScalarRetTy = Ctx.Types.inferScalarType(&R);
- Type *RetTy = VF.isVector() ? toVectorizedTy(ScalarRetTy, VF) : ScalarRetTy;
+ Type *RetTy =
+ VF.isVector() ? toVectorizedTy(ScalarRetTy, VF, ID) : ScalarRetTy;
SmallVector<Type *> ParamTys;
for (const VPValue *Op : Operands) {
ParamTys.push_back(VF.isVector()
diff --git a/llvm/unittests/IR/VectorTypeUtilsTest.cpp b/llvm/unittests/IR/VectorTypeUtilsTest.cpp
index c77f183e921de..5d4d30afa8fb0 100644
--- a/llvm/unittests/IR/VectorTypeUtilsTest.cpp
+++ b/llvm/unittests/IR/VectorTypeUtilsTest.cpp
@@ -8,6 +8,7 @@
#include "llvm/IR/VectorTypeUtils.h"
#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "gtest/gtest.h"
@@ -24,6 +25,7 @@ TEST(VectorTypeUtilsTest, TestToVectorizedTy) {
Type *FTy = Type::getFloatTy(C);
Type *HomogeneousStructTy = StructType::get(FTy, FTy, FTy);
Type *MixedStructTy = StructType::get(FTy, ITy);
+ Type *FFLoadRetTy = StructType::get(ITy, ITy);
Type *VoidTy = Type::getVoidTy(C);
for (ElementCount VF :
@@ -54,6 +56,11 @@ TEST(VectorTypeUtilsTest, TestToVectorizedTy) {
VectorType::get(ITy, VF));
EXPECT_EQ(toVectorizedTy(VoidTy, VF), VoidTy);
+ Type *WidenFFLoadRetTy =
+ toVectorizedTy(FFLoadRetTy, VF, Intrinsic::vp_load_ff);
+ EXPECT_EQ(cast<StructType>(WidenFFLoadRetTy)->getElementType(0),
+ VectorType::get(ITy, VF));
+ EXPECT_EQ(cast<StructType>(WidenFFLoadRetTy)->getElementType(1), ITy);
}
ElementCount ScalarVF = ElementCount::getFixed(1);
>From d3a43e5429839964f67d094ee62fa7fb0455293e Mon Sep 17 00:00:00 2001
From: ShihPo Hung <shihpo.hung at sifive.com>
Date: Wed, 3 Dec 2025 04:01:20 -0800
Subject: [PATCH 2/2] Split LV changes
---
llvm/lib/Analysis/VectorUtils.cpp | 4 ----
llvm/lib/Transforms/Vectorize/LoopVectorize.cpp | 6 +-----
llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp | 14 ++------------
3 files changed, 3 insertions(+), 21 deletions(-)
diff --git a/llvm/lib/Analysis/VectorUtils.cpp b/llvm/lib/Analysis/VectorUtils.cpp
index 85d1516f40c4c..a3e9b039f9225 100644
--- a/llvm/lib/Analysis/VectorUtils.cpp
+++ b/llvm/lib/Analysis/VectorUtils.cpp
@@ -224,10 +224,6 @@ bool llvm::isVectorIntrinsicWithStructReturnOverloadAtField(
return TTI->isTargetIntrinsicWithStructReturnOverloadAtField(ID, RetIdx);
switch (ID) {
- case Intrinsic::modf:
- case Intrinsic::sincos:
- case Intrinsic::sincospi:
- return false;
case Intrinsic::frexp:
return RetIdx == 0 || RetIdx == 1;
default:
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index b954d3f5ebe44..62b68232925d9 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -4139,11 +4139,7 @@ static bool willGenerateVectors(VPlan &Plan, ElementCount VF,
Type *ScalarTy = TypeInfo.inferScalarType(ToCheck);
if (!Visited.insert({ScalarTy}).second)
continue;
- unsigned IID = 0;
- if (auto *WI = dyn_cast<VPWidenIntrinsicRecipe>(&R))
- WI->getVectorIntrinsicID();
- Type *WideTy = toVectorizedTy(ScalarTy, VF, IID);
-
+ Type *WideTy = toVectorizedTy(ScalarTy, VF);
if (any_of(getContainedTypes(WideTy), WillGenerateTargetVectors))
return true;
}
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index a40df5084649f..0baf7172e4443 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -1679,16 +1679,7 @@ void VPWidenIntrinsicRecipe::execute(VPTransformState &State) {
SmallVector<Type *, 2> TysForDecl;
// Add return type if intrinsic is overloaded on it.
- if (ResultTy->isStructTy()) {
- auto *StructTy = cast<StructType>(ResultTy);
- for (unsigned I = 0, E = StructTy->getNumElements(); I != E; ++I) {
- if (isVectorIntrinsicWithStructReturnOverloadAtField(VectorIntrinsicID, I,
- State.TTI))
- TysForDecl.push_back(
- toVectorizedTy(StructTy->getStructElementType(I), State.VF));
- }
- } else if (isVectorIntrinsicWithOverloadTypeAtArg(VectorIntrinsicID, -1,
- State.TTI))
+ if (isVectorIntrinsicWithOverloadTypeAtArg(VectorIntrinsicID, -1, State.TTI))
TysForDecl.push_back(VectorType::get(getResultType(), State.VF));
SmallVector<Value *, 4> Args;
for (const auto &I : enumerate(operands())) {
@@ -1753,8 +1744,7 @@ static InstructionCost getCostForIntrinsics(Intrinsic::ID ID,
}
Type *ScalarRetTy = Ctx.Types.inferScalarType(&R);
- Type *RetTy =
- VF.isVector() ? toVectorizedTy(ScalarRetTy, VF, ID) : ScalarRetTy;
+ Type *RetTy = VF.isVector() ? toVectorizedTy(ScalarRetTy, VF) : ScalarRetTy;
SmallVector<Type *> ParamTys;
for (const VPValue *Op : Operands) {
ParamTys.push_back(VF.isVector()
More information about the llvm-commits
mailing list