Skip to content

Commit c8d2b06

Browse files
author
Francesco Petrogalli
committed
[llvm][LV] Replace unsigned VF with ElementCount VF [NFCI]
Changes: * Change `ToVectorTy` to deal directly with `ElementCount` instances. * `VF == 1` replaced with `VF.isScalar()`. * `VF > 1` and `VF >=2` replaced with `VF.isVector()`. * `VF <=1` is replaced with `VF.isZero() || VF.isScalar()`. * Add `<` operator to `ElementCount` to be able to use `llvm::SmallSetVector<ElementCount, ...>`. * Bits and pieces around printing the ElementCount to string streams. * Added a static method to `ElementCount` to represent a scalar. To guarantee that this change is a NFC, `VF.Min` and asserts are used in the following places: 1. When it doesn't make sense to deal with the scalable property, for example: a. When computing unrolling factors. b. When shuffle masks are built for fixed width vector types In this cases, an assert(!VF.Scalable && "<mgs>") has been added to make sure we don't enter coepaths that don't make sense for scalable vectors. 2. When there is a conscious decision to use `FixedVectorType`. These uses of `FixedVectorType` will likely be removed in favour of `VectorType` once the vectorizer is generic enough to deal with both fixed vector types and scalable vector types. 3. When dealing with building constants out of the value of VF, for example when computing the vectorization `step`, or building vectors of indices. These operation _make sense_ for scalable vectors too, but changing the code in these places to be generic and make it work for scalable vectors is to be submitted in a separate patch, as it is a functional change. 4. When building the potential VFs in VPlan. Making the VPlan generic enough to handle scalable vectorization factors is a functional change that needs a separate patch. See for example `void LoopVectorizationPlanner::buildVPlans(unsigned MinVF, unsigned MaxVF)`. 5. The class `IntrinsicCostAttribute`: this class still uses `unsigned VF` as updating the field to use `ElementCount` woudl require changes that could result in changing the behavior of the compiler. Will be done in a separate patch. 7. When dealing with user input for forcing the vectorization factor. In this case, adding support for scalable vectorization is a functional change that migh require changes at command line. Differential Revision: https://reviews.llvm.org/D85794
1 parent aec12c1 commit c8d2b06

File tree

9 files changed

+491
-335
lines changed

9 files changed

+491
-335
lines changed

llvm/include/llvm/Analysis/TargetTransformInfo.h

+5
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,11 @@ class IntrinsicCostAttributes {
128128

129129
IntrinsicCostAttributes(Intrinsic::ID Id, const CallBase &CI,
130130
unsigned Factor);
131+
IntrinsicCostAttributes(Intrinsic::ID Id, const CallBase &CI,
132+
ElementCount Factor)
133+
: IntrinsicCostAttributes(Id, CI, Factor.Min) {
134+
assert(!Factor.Scalable);
135+
}
131136

132137
IntrinsicCostAttributes(Intrinsic::ID Id, const CallBase &CI,
133138
unsigned Factor, unsigned ScalarCost);

llvm/include/llvm/Analysis/VectorUtils.h

+10-6
Original file line numberDiff line numberDiff line change
@@ -300,13 +300,17 @@ namespace Intrinsic {
300300
typedef unsigned ID;
301301
}
302302

303-
/// A helper function for converting Scalar types to vector types.
304-
/// If the incoming type is void, we return void. If the VF is 1, we return
305-
/// the scalar type.
306-
inline Type *ToVectorTy(Type *Scalar, unsigned VF, bool isScalable = false) {
307-
if (Scalar->isVoidTy() || VF == 1)
303+
/// A helper function for converting Scalar types to vector types. If
304+
/// the incoming type is void, we return void. If the EC represents a
305+
/// scalar, we return the scalar type.
306+
inline Type *ToVectorTy(Type *Scalar, ElementCount EC) {
307+
if (Scalar->isVoidTy() || EC.isScalar())
308308
return Scalar;
309-
return VectorType::get(Scalar, ElementCount::get(VF, isScalable));
309+
return VectorType::get(Scalar, EC);
310+
}
311+
312+
inline Type *ToVectorTy(Type *Scalar, unsigned VF) {
313+
return ToVectorTy(Scalar, ElementCount::getFixed(VF));
310314
}
311315

312316
/// Identify if the intrinsic is trivially vectorizable.

llvm/include/llvm/IR/DiagnosticInfo.h

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "llvm/ADT/Twine.h"
2222
#include "llvm/IR/DebugLoc.h"
2323
#include "llvm/Support/CBindingWrapping.h"
24+
#include "llvm/Support/TypeSize.h"
2425
#include "llvm/Support/YAMLTraits.h"
2526
#include <algorithm>
2627
#include <cstdint>
@@ -434,6 +435,7 @@ class DiagnosticInfoOptimizationBase : public DiagnosticInfoWithLocationBase {
434435
Argument(StringRef Key, unsigned N);
435436
Argument(StringRef Key, unsigned long N);
436437
Argument(StringRef Key, unsigned long long N);
438+
Argument(StringRef Key, ElementCount EC);
437439
Argument(StringRef Key, bool B) : Key(Key), Val(B ? "true" : "false") {}
438440
Argument(StringRef Key, DebugLoc dl);
439441
};

llvm/include/llvm/Support/TypeSize.h

+25
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,33 @@ class ElementCount {
6767
static ElementCount get(unsigned Min, bool Scalable) {
6868
return {Min, Scalable};
6969
}
70+
71+
/// Printing function.
72+
void print(raw_ostream &OS) const {
73+
if (Scalable)
74+
OS << "vscale x ";
75+
OS << Min;
76+
}
77+
/// Counting predicates.
78+
///
79+
/// Notice that Min = 1 and Scalable = true is considered more than
80+
/// one element.
81+
///
82+
///@{ No elements..
83+
bool isZero() const { return Min == 0; }
84+
/// Exactly one element.
85+
bool isScalar() const { return !Scalable && Min == 1; }
86+
/// One or more elements.
87+
bool isVector() const { return (Scalable && Min != 0) || Min > 1; }
88+
///@}
7089
};
7190

91+
/// Stream operator function for `ElementCount`.
92+
inline raw_ostream &operator<<(raw_ostream &OS, const ElementCount &EC) {
93+
EC.print(OS);
94+
return OS;
95+
}
96+
7297
// This class is used to represent the size of types. If the type is of fixed
7398
// size, it will represent the exact size. If the type is a scalable vector,
7499
// it will represent the known minimum size.

llvm/lib/IR/DiagnosticInfo.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,13 @@ DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key,
213213
unsigned long long N)
214214
: Key(std::string(Key)), Val(utostr(N)) {}
215215

216+
DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key,
217+
ElementCount EC)
218+
: Key(std::string(Key)) {
219+
raw_string_ostream OS(Val);
220+
EC.print(OS);
221+
}
222+
216223
DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, DebugLoc Loc)
217224
: Key(std::string(Key)), Loc(Loc) {
218225
if (Loc) {

llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.h

+12-7
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,14 @@ class VPBuilder {
172172
/// Information about vectorization costs
173173
struct VectorizationFactor {
174174
// Vector width with best cost
175-
unsigned Width;
175+
ElementCount Width;
176176
// Cost of the loop with that width
177177
unsigned Cost;
178178

179179
// Width 1 means no vectorization, cost 0 means uncomputed cost.
180-
static VectorizationFactor Disabled() { return {1, 0}; }
180+
static VectorizationFactor Disabled() {
181+
return {ElementCount::getFixed(1), 0};
182+
}
181183

182184
bool operator==(const VectorizationFactor &rhs) const {
183185
return Width == rhs.Width && Cost == rhs.Cost;
@@ -227,7 +229,10 @@ class LoopVectorizationPlanner {
227229
/// A builder used to construct the current plan.
228230
VPBuilder Builder;
229231

230-
unsigned BestVF = 0;
232+
/// The best number of elements of the vector types used in the
233+
/// transformed loop. BestVF = None means that vectorization is
234+
/// disabled.
235+
Optional<ElementCount> BestVF = None;
231236
unsigned BestUF = 0;
232237

233238
public:
@@ -242,14 +247,14 @@ class LoopVectorizationPlanner {
242247

243248
/// Plan how to best vectorize, return the best VF and its cost, or None if
244249
/// vectorization and interleaving should be avoided up front.
245-
Optional<VectorizationFactor> plan(unsigned UserVF, unsigned UserIC);
250+
Optional<VectorizationFactor> plan(ElementCount UserVF, unsigned UserIC);
246251

247252
/// Use the VPlan-native path to plan how to best vectorize, return the best
248253
/// VF and its cost.
249-
VectorizationFactor planInVPlanNativePath(unsigned UserVF);
254+
VectorizationFactor planInVPlanNativePath(ElementCount UserVF);
250255

251256
/// Finalize the best decision and dispose of all other VPlans.
252-
void setBestPlan(unsigned VF, unsigned UF);
257+
void setBestPlan(ElementCount VF, unsigned UF);
253258

254259
/// Generate the IR code for the body of the vectorized loop according to the
255260
/// best selected VPlan.
@@ -264,7 +269,7 @@ class LoopVectorizationPlanner {
264269
/// \p Predicate on Range.Start, possibly decreasing Range.End such that the
265270
/// returned value holds for the entire \p Range.
266271
static bool
267-
getDecisionAndClampRange(const std::function<bool(unsigned)> &Predicate,
272+
getDecisionAndClampRange(const std::function<bool(ElementCount)> &Predicate,
268273
VFRange &Range);
269274

270275
protected:

0 commit comments

Comments
 (0)