Skip to content

Commit d2643e2

Browse files
committed
Initial changes picked over from #109833
1 parent 9ee9e0e commit d2643e2

File tree

9 files changed

+180
-42
lines changed

9 files changed

+180
-42
lines changed

llvm/include/llvm/Analysis/VectorUtils.h

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "llvm/Analysis/LoopAccessAnalysis.h"
1919
#include "llvm/IR/Module.h"
2020
#include "llvm/IR/VFABIDemangler.h"
21+
#include "llvm/IR/VectorUtils.h"
2122
#include "llvm/Support/CheckedArithmetic.h"
2223

2324
namespace llvm {
@@ -127,18 +128,8 @@ namespace Intrinsic {
127128
typedef unsigned ID;
128129
}
129130

130-
/// A helper function for converting Scalar types to vector types. If
131-
/// the incoming type is void, we return void. If the EC represents a
132-
/// scalar, we return the scalar type.
133-
inline Type *ToVectorTy(Type *Scalar, ElementCount EC) {
134-
if (Scalar->isVoidTy() || Scalar->isMetadataTy() || EC.isScalar())
135-
return Scalar;
136-
return VectorType::get(Scalar, EC);
137-
}
138-
139-
inline Type *ToVectorTy(Type *Scalar, unsigned VF) {
140-
return ToVectorTy(Scalar, ElementCount::getFixed(VF));
141-
}
131+
/// Returns true if `Ty` can be widened by the loop vectorizer.
132+
bool canWidenType(Type *Ty);
142133

143134
/// Identify if the intrinsic is trivially vectorizable.
144135
/// This method returns true if the intrinsic's argument types are all scalars

llvm/include/llvm/IR/VectorUtils.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//===----------- VectorUtils.h - Vector type utility functions -*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "llvm/ADT/SmallVector.h"
10+
#include "llvm/IR/DerivedTypes.h"
11+
12+
namespace llvm {
13+
14+
/// A helper function for converting Scalar types to vector types. If
15+
/// the incoming type is void, we return void. If the EC represents a
16+
/// scalar, we return the scalar type.
17+
inline Type *ToVectorTy(Type *Scalar, ElementCount EC) {
18+
if (Scalar->isVoidTy() || Scalar->isMetadataTy() || EC.isScalar())
19+
return Scalar;
20+
return VectorType::get(Scalar, EC);
21+
}
22+
23+
inline Type *ToVectorTy(Type *Scalar, unsigned VF) {
24+
return ToVectorTy(Scalar, ElementCount::getFixed(VF));
25+
}
26+
27+
/// A helper for converting to wider (vector) types. For scalar types, this is
28+
/// equivalent to calling `ToVectorTy`. For struct types, this returns a new
29+
/// struct where each element type has been widened to a vector type. Note: Only
30+
/// unpacked literal struct types are supported.
31+
Type *ToWideTy(Type *Ty, ElementCount EC);
32+
33+
/// A helper for converting wide types to narrow (non-vector) types. For vector
34+
/// types, this is equivalent to calling .getScalarType(). For struct types,
35+
/// this returns a new struct where each element type has been converted to a
36+
/// scalar type. Note: Only unpacked literal struct types are supported.
37+
Type *ToNarrowTy(Type *Ty);
38+
39+
/// Returns the types contained in `Ty`. For struct types, it returns the
40+
/// elements, all other types are returned directly.
41+
SmallVector<Type *, 2> getContainedTypes(Type *Ty);
42+
43+
/// Returns true if `Ty` is a vector type or a struct of vector types where all
44+
/// vector types share the same VF.
45+
bool isWideTy(Type *Ty);
46+
47+
/// Returns the vectorization factor for a widened type.
48+
inline ElementCount getWideTypeVF(Type *Ty) {
49+
assert(isWideTy(Ty) && "expected widened type!");
50+
return cast<VectorType>(getContainedTypes(Ty).front())->getElementCount();
51+
}
52+
53+
} // namespace llvm

llvm/lib/Analysis/VectorUtils.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,20 @@ static cl::opt<unsigned> MaxInterleaveGroupFactor(
3939
cl::desc("Maximum factor for an interleaved access group (default = 8)"),
4040
cl::init(8));
4141

42+
/// Returns true if `Ty` can be widened by the loop vectorizer.
43+
bool llvm::canWidenType(Type *Ty) {
44+
Type *ElTy = Ty;
45+
// For now, only allow widening non-packed literal structs where all
46+
// element types are the same. This simplifies the cost model and
47+
// conversion between scalar and wide types.
48+
if (auto *StructTy = dyn_cast<StructType>(Ty);
49+
StructTy && !StructTy->isPacked() && StructTy->isLiteral() &&
50+
StructTy->containsHomogeneousTypes()) {
51+
ElTy = StructTy->elements().front();
52+
}
53+
return VectorType::isValidElementType(ElTy);
54+
}
55+
4256
/// Return true if all of the intrinsic's arguments and return type are scalars
4357
/// for the scalar form of the intrinsic, and vectors for the vector form of the
4458
/// intrinsic (except operands that are marked as always being scalar by

llvm/lib/IR/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ add_llvm_component_library(LLVMCore
7373
Value.cpp
7474
ValueSymbolTable.cpp
7575
VectorBuilder.cpp
76+
VectorUtils.cpp
7677
Verifier.cpp
7778
VFABIDemangler.cpp
7879
RuntimeLibcalls.cpp

llvm/lib/IR/VFABIDemangler.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "llvm/ADT/SmallString.h"
1212
#include "llvm/ADT/StringSwitch.h"
1313
#include "llvm/IR/Module.h"
14+
#include "llvm/IR/VectorUtils.h"
1415
#include "llvm/Support/Debug.h"
1516
#include "llvm/Support/raw_ostream.h"
1617
#include <limits>
@@ -346,12 +347,15 @@ getScalableECFromSignature(const FunctionType *Signature, const VFISAKind ISA,
346347
// Also check the return type if not void.
347348
Type *RetTy = Signature->getReturnType();
348349
if (!RetTy->isVoidTy()) {
349-
std::optional<ElementCount> ReturnEC = getElementCountForTy(ISA, RetTy);
350-
// If we have an unknown scalar element type we can't find a reasonable VF.
351-
if (!ReturnEC)
352-
return std::nullopt;
353-
if (ElementCount::isKnownLT(*ReturnEC, MinEC))
354-
MinEC = *ReturnEC;
350+
for (Type *RetTy : getContainedTypes(RetTy)) {
351+
std::optional<ElementCount> ReturnEC = getElementCountForTy(ISA, RetTy);
352+
// If we have an unknown scalar element type we can't find a reasonable
353+
// VF.
354+
if (!ReturnEC)
355+
return std::nullopt;
356+
if (ElementCount::isKnownLT(*ReturnEC, MinEC))
357+
MinEC = *ReturnEC;
358+
}
355359
}
356360

357361
// The SVE Vector function call ABI bases the VF on the widest element types
@@ -566,7 +570,7 @@ FunctionType *VFABI::createFunctionType(const VFInfo &Info,
566570

567571
auto *RetTy = ScalarFTy->getReturnType();
568572
if (!RetTy->isVoidTy())
569-
RetTy = VectorType::get(RetTy, VF);
573+
RetTy = ToWideTy(RetTy, VF);
570574
return FunctionType::get(RetTy, VecTypes, false);
571575
}
572576

llvm/lib/IR/VectorUtils.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//===----------- VectorUtils.cpp - Vector type utility functions ----------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "llvm/IR/VectorUtils.h"
10+
#include "llvm/ADT/SmallVectorExtras.h"
11+
12+
using namespace llvm;
13+
14+
/// A helper for converting to wider (vector) types. For scalar types, this is
15+
/// equivalent to calling `ToVectorTy`. For struct types, this returns a new
16+
/// struct where each element type has been widened to a vector type. Note: Only
17+
/// unpacked literal struct types are supported.
18+
Type *llvm::ToWideTy(Type *Ty, ElementCount EC) {
19+
if (EC.isScalar())
20+
return Ty;
21+
auto *StructTy = dyn_cast<StructType>(Ty);
22+
if (!StructTy)
23+
return ToVectorTy(Ty, EC);
24+
assert(StructTy->isLiteral() && !StructTy->isPacked() &&
25+
"expected unpacked struct literal");
26+
return StructType::get(
27+
Ty->getContext(),
28+
map_to_vector(StructTy->elements(), [&](Type *ElTy) -> Type * {
29+
return VectorType::get(ElTy, EC);
30+
}));
31+
}
32+
33+
/// A helper for converting wide types to narrow (non-vector) types. For vector
34+
/// types, this is equivalent to calling .getScalarType(). For struct types,
35+
/// this returns a new struct where each element type has been converted to a
36+
/// scalar type. Note: Only unpacked literal struct types are supported.
37+
Type *llvm::ToNarrowTy(Type *Ty) {
38+
auto *StructTy = dyn_cast<StructType>(Ty);
39+
if (!StructTy)
40+
return Ty->getScalarType();
41+
assert(StructTy->isLiteral() && !StructTy->isPacked() &&
42+
"expected unpacked struct literal");
43+
return StructType::get(
44+
Ty->getContext(),
45+
map_to_vector(StructTy->elements(), [](Type *ElTy) -> Type * {
46+
return ElTy->getScalarType();
47+
}));
48+
}
49+
50+
/// Returns the types contained in `Ty`. For struct types, it returns the
51+
/// elements, all other types are returned directly.
52+
SmallVector<Type *, 2> llvm::getContainedTypes(Type *Ty) {
53+
auto *StructTy = dyn_cast<StructType>(Ty);
54+
if (StructTy)
55+
return to_vector<2>(StructTy->elements());
56+
return {Ty};
57+
}
58+
59+
/// Returns true if `Ty` is a vector type or a struct of vector types where all
60+
/// vector types share the same VF.
61+
bool llvm::isWideTy(Type *Ty) {
62+
auto ContainedTys = getContainedTypes(Ty);
63+
if (ContainedTys.empty() || !ContainedTys.front()->isVectorTy())
64+
return false;
65+
ElementCount VF = cast<VectorType>(ContainedTys.front())->getElementCount();
66+
return all_of(ContainedTys, [&](Type *Ty) {
67+
return Ty->isVectorTy() && cast<VectorType>(Ty)->getElementCount() == VF;
68+
});
69+
}

llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -949,8 +949,8 @@ bool LoopVectorizationLegality::canVectorizeInstrs() {
949949
// Check that the instruction return type is vectorizable.
950950
// We can't vectorize casts from vector type to scalar type.
951951
// Also, we can't vectorize extractelement instructions.
952-
if ((!VectorType::isValidElementType(I.getType()) &&
953-
!I.getType()->isVoidTy()) ||
952+
Type *InstTy = I.getType();
953+
if (!(InstTy->isVoidTy() || canWidenType(InstTy)) ||
954954
(isa<CastInst>(I) &&
955955
!VectorType::isValidElementType(I.getOperand(0)->getType())) ||
956956
isa<ExtractElementInst>(I)) {

llvm/lib/Transforms/Vectorize/LoopVectorize.cpp

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2861,10 +2861,10 @@ LoopVectorizationCostModel::getVectorCallCost(CallInst *CI,
28612861
return ScalarCallCost;
28622862
}
28632863

2864-
static Type *maybeVectorizeType(Type *Elt, ElementCount VF) {
2865-
if (VF.isScalar() || (!Elt->isIntOrPtrTy() && !Elt->isFloatingPointTy()))
2866-
return Elt;
2867-
return VectorType::get(Elt, VF);
2864+
static Type *maybeVectorizeType(Type *Ty, ElementCount VF) {
2865+
if (VF.isScalar() || !canWidenType(Ty))
2866+
return Ty;
2867+
return ToWideTy(Ty, VF);
28682868
}
28692869

28702870
InstructionCost
@@ -3635,9 +3635,8 @@ void LoopVectorizationCostModel::collectLoopUniforms(ElementCount VF) {
36353635

36363636
// ExtractValue instructions must be uniform, because the operands are
36373637
// known to be loop-invariant.
3638-
if (auto *EVI = dyn_cast<ExtractValueInst>(&I)) {
3639-
assert(IsOutOfScope(EVI->getAggregateOperand()) &&
3640-
"Expected aggregate value to be loop invariant");
3638+
if (auto *EVI = dyn_cast<ExtractValueInst>(&I);
3639+
EVI && IsOutOfScope(EVI->getAggregateOperand())) {
36413640
AddToWorklistIfAllowed(EVI);
36423641
continue;
36433642
}
@@ -5461,10 +5460,13 @@ InstructionCost LoopVectorizationCostModel::computePredInstDiscount(
54615460
// and phi nodes.
54625461
TTI::TargetCostKind CostKind = TTI::TCK_RecipThroughput;
54635462
if (isScalarWithPredication(I, VF) && !I->getType()->isVoidTy()) {
5464-
ScalarCost += TTI.getScalarizationOverhead(
5465-
cast<VectorType>(ToVectorTy(I->getType(), VF)),
5466-
APInt::getAllOnes(VF.getFixedValue()), /*Insert*/ true,
5467-
/*Extract*/ false, CostKind);
5463+
Type *WideTy = ToWideTy(I->getType(), VF);
5464+
for (Type *VectorTy : getContainedTypes(WideTy)) {
5465+
ScalarCost += TTI.getScalarizationOverhead(
5466+
cast<VectorType>(VectorTy), APInt::getAllOnes(VF.getFixedValue()),
5467+
/*Insert*/ true,
5468+
/*Extract*/ false, CostKind);
5469+
}
54685470
ScalarCost +=
54695471
VF.getFixedValue() * TTI.getCFInstrCost(Instruction::PHI, CostKind);
54705472
}
@@ -5953,13 +5955,17 @@ InstructionCost LoopVectorizationCostModel::getScalarizationOverhead(
59535955
return 0;
59545956

59555957
InstructionCost Cost = 0;
5956-
Type *RetTy = ToVectorTy(I->getType(), VF);
5958+
Type *RetTy = ToWideTy(I->getType(), VF);
59575959
if (!RetTy->isVoidTy() &&
5958-
(!isa<LoadInst>(I) || !TTI.supportsEfficientVectorElementLoadStore()))
5959-
Cost += TTI.getScalarizationOverhead(
5960-
cast<VectorType>(RetTy), APInt::getAllOnes(VF.getKnownMinValue()),
5961-
/*Insert*/ true,
5962-
/*Extract*/ false, CostKind);
5960+
(!isa<LoadInst>(I) || !TTI.supportsEfficientVectorElementLoadStore())) {
5961+
5962+
for (Type *VectorTy : getContainedTypes(RetTy)) {
5963+
Cost += TTI.getScalarizationOverhead(
5964+
cast<VectorType>(VectorTy), APInt::getAllOnes(VF.getKnownMinValue()),
5965+
/*Insert*/ true,
5966+
/*Extract*/ false, CostKind);
5967+
}
5968+
}
59635969

59645970
// Some targets keep addresses scalar.
59655971
if (isa<LoadInst>(I) && !TTI.prefersVectorizedAddressing())
@@ -6219,9 +6225,9 @@ void LoopVectorizationCostModel::setVectorizedCallDecision(ElementCount VF) {
62196225

62206226
bool MaskRequired = Legal->isMaskRequired(CI);
62216227
// Compute corresponding vector type for return value and arguments.
6222-
Type *RetTy = ToVectorTy(ScalarRetTy, VF);
6228+
Type *RetTy = ToWideTy(ScalarRetTy, VF);
62236229
for (Type *ScalarTy : ScalarTys)
6224-
Tys.push_back(ToVectorTy(ScalarTy, VF));
6230+
Tys.push_back(ToWideTy(ScalarTy, VF));
62256231

62266232
// An in-loop reduction using an fmuladd intrinsic is a special case;
62276233
// we don't want the normal cost for that intrinsic.
@@ -6398,7 +6404,7 @@ LoopVectorizationCostModel::getInstructionCost(Instruction *I,
63986404
HasSingleCopyAfterVectorization(I, VF));
63996405
VectorTy = RetTy;
64006406
} else
6401-
VectorTy = ToVectorTy(RetTy, VF);
6407+
VectorTy = ToWideTy(RetTy, VF);
64026408

64036409
if (VF.isVector() && VectorTy->isVectorTy() &&
64046410
!TTI.getNumberOfParts(VectorTy))

llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1026,7 +1026,7 @@ InstructionCost VPWidenIntrinsicRecipe::computeCost(ElementCount VF,
10261026
Arguments.push_back(V);
10271027
}
10281028

1029-
Type *RetTy = ToVectorTy(Ctx.Types.inferScalarType(this), VF);
1029+
Type *RetTy = ToWideTy(Ctx.Types.inferScalarType(this), VF);
10301030
SmallVector<Type *> ParamTys;
10311031
for (unsigned I = 0; I != getNumOperands(); ++I)
10321032
ParamTys.push_back(

0 commit comments

Comments
 (0)