7
7
// ===----------------------------------------------------------------------===//
8
8
9
9
#include " llvm/Analysis/VectorUtils.h"
10
+ #include " llvm/Support/Debug.h"
11
+ #include " llvm/Support/raw_ostream.h"
12
+ #include < limits>
10
13
11
14
using namespace llvm ;
12
15
16
+ #define DEBUG_TYPE " vfabi-demangling"
17
+
13
18
namespace {
14
19
// / Utilities for the Vector Function ABI name parser.
15
20
@@ -21,8 +26,9 @@ enum class ParseRet {
21
26
};
22
27
23
28
// / Extracts the `<isa>` information from the mangled string, and
24
- // / sets the `ISA` accordingly.
25
- ParseRet tryParseISA (StringRef &MangledName, VFISAKind &ISA) {
29
+ // / sets the `ISA` accordingly. If successful, the <isa> token is removed
30
+ // / from the input string `MangledName`.
31
+ static ParseRet tryParseISA (StringRef &MangledName, VFISAKind &ISA) {
26
32
if (MangledName.empty ())
27
33
return ParseRet::Error;
28
34
@@ -45,9 +51,9 @@ ParseRet tryParseISA(StringRef &MangledName, VFISAKind &ISA) {
45
51
}
46
52
47
53
// / Extracts the `<mask>` information from the mangled string, and
48
- // / sets `IsMasked` accordingly. The input string `MangledName` is
49
- // / left unmodified .
50
- ParseRet tryParseMask (StringRef &MangledName, bool &IsMasked) {
54
+ // / sets `IsMasked` accordingly. If successful, the <mask> token is removed
55
+ // / from the input string `MangledName` .
56
+ static ParseRet tryParseMask (StringRef &MangledName, bool &IsMasked) {
51
57
if (MangledName.consume_front (" M" )) {
52
58
IsMasked = true ;
53
59
return ParseRet::OK;
@@ -62,28 +68,36 @@ ParseRet tryParseMask(StringRef &MangledName, bool &IsMasked) {
62
68
}
63
69
64
70
// / Extract the `<vlen>` information from the mangled string, and
65
- // / sets `VF` accordingly. A `<vlen> == "x"` token is interpreted as a scalable
66
- // / vector length. On success, the `<vlen>` token is removed from
67
- // / the input string `ParseString`.
68
- // /
69
- ParseRet tryParseVLEN (StringRef &ParseString, unsigned &VF, bool &IsScalable) {
71
+ // / sets `ParsedVF` accordingly. A `<vlen> == "x"` token is interpreted as a
72
+ // / scalable vector length and the boolean is set to true, otherwise a nonzero
73
+ // / unsigned integer will be directly used as a VF. On success, the `<vlen>`
74
+ // / token is removed from the input string `ParseString`.
75
+ static ParseRet tryParseVLEN (StringRef &ParseString, VFISAKind ISA,
76
+ std::pair<unsigned , bool > &ParsedVF) {
70
77
if (ParseString.consume_front (" x" )) {
71
- // Set VF to 0, to be later adjusted to a value grater than zero
72
- // by looking at the signature of the vector function with
73
- // `getECFromSignature`.
74
- VF = 0 ;
75
- IsScalable = true ;
78
+ // SVE is the only scalable ISA currently supported.
79
+ if (ISA != VFISAKind::SVE) {
80
+ LLVM_DEBUG (dbgs () << " Vector function variant declared with scalable VF "
81
+ << " but ISA is not SVE\n " );
82
+ return ParseRet::Error;
83
+ }
84
+ // We can't determine the VF of a scalable vector by looking at the vlen
85
+ // string (just 'x'), so say we successfully parsed it but return a 'true'
86
+ // for the scalable field with an invalid VF field so that we know to look
87
+ // up the actual VF based on element types from the parameters or return.
88
+ ParsedVF = {0 , true };
76
89
return ParseRet::OK;
77
90
}
78
91
92
+ unsigned VF = 0 ;
79
93
if (ParseString.consumeInteger (10 , VF))
80
94
return ParseRet::Error;
81
95
82
96
// The token `0` is invalid for VLEN.
83
97
if (VF == 0 )
84
98
return ParseRet::Error;
85
99
86
- IsScalable = false ;
100
+ ParsedVF = {VF, false } ;
87
101
return ParseRet::OK;
88
102
}
89
103
@@ -99,9 +113,9 @@ ParseRet tryParseVLEN(StringRef &ParseString, unsigned &VF, bool &IsScalable) {
99
113
// /
100
114
// / The function expects <token> to be one of "ls", "Rs", "Us" or
101
115
// / "Ls".
102
- ParseRet tryParseLinearTokenWithRuntimeStep (StringRef &ParseString,
103
- VFParamKind &PKind, int &Pos,
104
- const StringRef Token) {
116
+ static ParseRet tryParseLinearTokenWithRuntimeStep (StringRef &ParseString,
117
+ VFParamKind &PKind, int &Pos,
118
+ const StringRef Token) {
105
119
if (ParseString.consume_front (Token)) {
106
120
PKind = VFABI::getVFParamKindFromString (Token);
107
121
if (ParseString.consumeInteger (10 , Pos))
@@ -123,8 +137,9 @@ ParseRet tryParseLinearTokenWithRuntimeStep(StringRef &ParseString,
123
137
// / sets `PKind` to the correspondent enum value, sets `StepOrPos` to
124
138
// / <number>, and return success. On a syntax error, it return a
125
139
// / parsing error. If nothing is parsed, it returns std::nullopt.
126
- ParseRet tryParseLinearWithRuntimeStep (StringRef &ParseString,
127
- VFParamKind &PKind, int &StepOrPos) {
140
+ static ParseRet tryParseLinearWithRuntimeStep (StringRef &ParseString,
141
+ VFParamKind &PKind,
142
+ int &StepOrPos) {
128
143
ParseRet Ret;
129
144
130
145
// "ls" <RuntimeStepPos>
@@ -162,9 +177,10 @@ ParseRet tryParseLinearWithRuntimeStep(StringRef &ParseString,
162
177
// /
163
178
// / The function expects <token> to be one of "l", "R", "U" or
164
179
// / "L".
165
- ParseRet tryParseCompileTimeLinearToken (StringRef &ParseString,
166
- VFParamKind &PKind, int &LinearStep,
167
- const StringRef Token) {
180
+ static ParseRet tryParseCompileTimeLinearToken (StringRef &ParseString,
181
+ VFParamKind &PKind,
182
+ int &LinearStep,
183
+ const StringRef Token) {
168
184
if (ParseString.consume_front (Token)) {
169
185
PKind = VFABI::getVFParamKindFromString (Token);
170
186
const bool Negate = ParseString.consume_front (" n" );
@@ -187,8 +203,9 @@ ParseRet tryParseCompileTimeLinearToken(StringRef &ParseString,
187
203
// / sets `PKind` to the correspondent enum value, sets `LinearStep` to
188
204
// / <number>, and return success. On a syntax error, it return a
189
205
// / parsing error. If nothing is parsed, it returns std::nullopt.
190
- ParseRet tryParseLinearWithCompileTimeStep (StringRef &ParseString,
191
- VFParamKind &PKind, int &StepOrPos) {
206
+ static ParseRet tryParseLinearWithCompileTimeStep (StringRef &ParseString,
207
+ VFParamKind &PKind,
208
+ int &StepOrPos) {
192
209
// "l" {"n"} <CompileTimeStep>
193
210
if (tryParseCompileTimeLinearToken (ParseString, PKind, StepOrPos, " l" ) ==
194
211
ParseRet::OK)
@@ -220,8 +237,8 @@ ParseRet tryParseLinearWithCompileTimeStep(StringRef &ParseString,
220
237
// / sets `PKind` to the correspondent enum value, sets `StepOrPos`
221
238
// / accordingly, and return success. On a syntax error, it return a
222
239
// / parsing error. If nothing is parsed, it returns std::nullopt.
223
- ParseRet tryParseParameter (StringRef &ParseString, VFParamKind &PKind,
224
- int &StepOrPos) {
240
+ static ParseRet tryParseParameter (StringRef &ParseString, VFParamKind &PKind,
241
+ int &StepOrPos) {
225
242
if (ParseString.consume_front (" v" )) {
226
243
PKind = VFParamKind::Vector;
227
244
StepOrPos = 0 ;
@@ -255,7 +272,7 @@ ParseRet tryParseParameter(StringRef &ParseString, VFParamKind &PKind,
255
272
// / sets `PKind` to the correspondent enum value, sets `StepOrPos`
256
273
// / accordingly, and return success. On a syntax error, it return a
257
274
// / parsing error. If nothing is parsed, it returns std::nullopt.
258
- ParseRet tryParseAlign (StringRef &ParseString, Align &Alignment) {
275
+ static ParseRet tryParseAlign (StringRef &ParseString, Align &Alignment) {
259
276
uint64_t Val;
260
277
// "a" <number>
261
278
if (ParseString.consume_front (" a" )) {
@@ -273,49 +290,86 @@ ParseRet tryParseAlign(StringRef &ParseString, Align &Alignment) {
273
290
return ParseRet::None;
274
291
}
275
292
276
- #ifndef NDEBUG
277
- // Verify the assumtion that all vectors in the signature of a vector
278
- // function have the same number of elements.
279
- bool verifyAllVectorsHaveSameWidth (FunctionType *Signature) {
280
- SmallVector<VectorType *, 2 > VecTys;
281
- if (auto *RetTy = dyn_cast<VectorType>(Signature->getReturnType ()))
282
- VecTys.push_back (RetTy);
283
- for (auto *Ty : Signature->params ())
284
- if (auto *VTy = dyn_cast<VectorType>(Ty))
285
- VecTys.push_back (VTy);
286
-
287
- if (VecTys.size () <= 1 )
288
- return true ;
289
-
290
- assert (VecTys.size () > 1 && " Invalid number of elements." );
291
- const ElementCount EC = VecTys[0 ]->getElementCount ();
292
- return llvm::all_of (llvm::drop_begin (VecTys), [&EC](VectorType *VTy) {
293
- return (EC == VTy->getElementCount ());
294
- });
293
+ // Returns the 'natural' VF for a given scalar element type, based on the
294
+ // current architecture.
295
+ //
296
+ // For SVE (currently the only scalable architecture with a defined name
297
+ // mangling), we assume a minimum vector size of 128b and return a VF based on
298
+ // the number of elements of the given type which would fit in such a vector.
299
+ static std::optional<ElementCount> getElementCountForTy (const VFISAKind ISA,
300
+ const Type *Ty) {
301
+ // Only AArch64 SVE is supported at present.
302
+ assert (ISA == VFISAKind::SVE &&
303
+ " Scalable VF decoding only implemented for SVE\n " );
304
+
305
+ if (Ty->isIntegerTy (64 ) || Ty->isDoubleTy () || Ty->isPointerTy ())
306
+ return ElementCount::getScalable (2 );
307
+ if (Ty->isIntegerTy (32 ) || Ty->isFloatTy ())
308
+ return ElementCount::getScalable (4 );
309
+ if (Ty->isIntegerTy (16 ) || Ty->is16bitFPTy ())
310
+ return ElementCount::getScalable (8 );
311
+ if (Ty->isIntegerTy (8 ))
312
+ return ElementCount::getScalable (16 );
313
+
314
+ return std::nullopt;
295
315
}
296
- #endif // NDEBUG
297
-
298
- // Extract the VectorizationFactor from a given function signature,
299
- // under the assumtion that all vectors have the same number of
300
- // elements, i.e. same ElementCount.Min.
301
- ElementCount getECFromSignature (FunctionType *Signature) {
302
- assert (verifyAllVectorsHaveSameWidth (Signature) &&
303
- " Invalid vector signature." );
304
-
305
- if (auto *RetTy = dyn_cast<VectorType>(Signature->getReturnType ()))
306
- return RetTy->getElementCount ();
307
- for (auto *Ty : Signature->params ())
308
- if (auto *VTy = dyn_cast<VectorType>(Ty))
309
- return VTy->getElementCount ();
310
-
311
- return ElementCount::getFixed (/* Min=*/ 1 );
316
+
317
+ // Extract the VectorizationFactor from a given function signature, based
318
+ // on the widest scalar element types that will become vector parameters.
319
+ static std::optional<ElementCount>
320
+ getScalableECFromSignature (const FunctionType *Signature, const VFISAKind ISA,
321
+ const SmallVectorImpl<VFParameter> &Params) {
322
+ // Start with a very wide EC and drop when we find smaller ECs based on type.
323
+ ElementCount MinEC =
324
+ ElementCount::getScalable (std::numeric_limits<unsigned int >::max ());
325
+ for (auto &Param : Params) {
326
+ // Only vector parameters are used when determining the VF; uniform or
327
+ // linear are left as scalars, so do not affect VF.
328
+ if (Param.ParamKind == VFParamKind::Vector) {
329
+ // If the scalar function doesn't actually have a corresponding argument,
330
+ // reject the mapping.
331
+ if (Param.ParamPos >= Signature->getNumParams ())
332
+ return std::nullopt;
333
+ Type *PTy = Signature->getParamType (Param.ParamPos );
334
+
335
+ std::optional<ElementCount> EC = getElementCountForTy (ISA, PTy);
336
+ // If we have an unknown scalar element type we can't find a reasonable
337
+ // VF.
338
+ if (!EC)
339
+ return std::nullopt;
340
+
341
+ // Find the smallest VF, based on the widest scalar type.
342
+ if (ElementCount::isKnownLT (*EC, MinEC))
343
+ MinEC = *EC;
344
+ }
345
+ }
346
+
347
+ // Also check the return type if not void.
348
+ Type *RetTy = Signature->getReturnType ();
349
+ if (!RetTy->isVoidTy ()) {
350
+ std::optional<ElementCount> ReturnEC = getElementCountForTy (ISA, RetTy);
351
+ // If we have an unknown scalar element type we can't find a reasonable VF.
352
+ if (!ReturnEC)
353
+ return std::nullopt;
354
+ if (ElementCount::isKnownLT (*ReturnEC, MinEC))
355
+ MinEC = *ReturnEC;
356
+ }
357
+
358
+ // The SVE Vector function call ABI bases the VF on the widest element types
359
+ // present, and vector arguments containing types of that width are always
360
+ // considered to be packed. Arguments with narrower elements are considered
361
+ // to be unpacked.
362
+ if (MinEC.getKnownMinValue () < std::numeric_limits<unsigned int >::max ())
363
+ return MinEC;
364
+
365
+ return std::nullopt;
312
366
}
313
367
} // namespace
314
368
315
369
// Format of the ABI name:
316
370
// _ZGV<isa><mask><vlen><parameters>_<scalarname>[(<redirection>)]
317
371
std::optional<VFInfo> VFABI::tryDemangleForVFABI (StringRef MangledName,
318
- const Module &M ) {
372
+ const CallInst &CI ) {
319
373
const StringRef OriginalName = MangledName;
320
374
// Assume there is no custom name <redirection>, and therefore the
321
375
// vector name consists of
@@ -338,9 +392,8 @@ std::optional<VFInfo> VFABI::tryDemangleForVFABI(StringRef MangledName,
338
392
return std::nullopt;
339
393
340
394
// Parse the variable size, starting from <vlen>.
341
- unsigned VF;
342
- bool IsScalable;
343
- if (tryParseVLEN (MangledName, VF, IsScalable) != ParseRet::OK)
395
+ std::pair<unsigned , bool > ParsedVF;
396
+ if (tryParseVLEN (MangledName, ISA, ParsedVF) != ParseRet::OK)
344
397
return std::nullopt;
345
398
346
399
// Parse the <parameters>.
@@ -374,6 +427,19 @@ std::optional<VFInfo> VFABI::tryDemangleForVFABI(StringRef MangledName,
374
427
if (Parameters.empty ())
375
428
return std::nullopt;
376
429
430
+ // Figure out the number of lanes in vectors for this function variant. This
431
+ // is easy for fixed length, as the vlen encoding just gives us the value
432
+ // directly. However, if the vlen mangling indicated that this function
433
+ // variant expects scalable vectors we need to work it out based on the
434
+ // demangled parameter types and the scalar function signature.
435
+ std::optional<ElementCount> EC;
436
+ if (ParsedVF.second ) {
437
+ EC = getScalableECFromSignature (CI.getFunctionType (), ISA, Parameters);
438
+ if (!EC)
439
+ return std::nullopt;
440
+ } else
441
+ EC = ElementCount::getFixed (ParsedVF.first );
442
+
377
443
// Check for the <scalarname> and the optional <redirection>, which
378
444
// are separated from the prefix with "_"
379
445
if (!MangledName.consume_front (" _" ))
@@ -426,32 +492,7 @@ std::optional<VFInfo> VFABI::tryDemangleForVFABI(StringRef MangledName,
426
492
assert (Parameters.back ().ParamKind == VFParamKind::GlobalPredicate &&
427
493
" The global predicate must be the last parameter" );
428
494
429
- // Adjust the VF for scalable signatures. The EC.Min is not encoded
430
- // in the name of the function, but it is encoded in the IR
431
- // signature of the function. We need to extract this information
432
- // because it is needed by the loop vectorizer, which reasons in
433
- // terms of VectorizationFactor or ElementCount. In particular, we
434
- // need to make sure that the VF field of the VFShape class is never
435
- // set to 0.
436
- if (IsScalable) {
437
- const Function *F = M.getFunction (VectorName);
438
- // The declaration of the function must be present in the module
439
- // to be able to retrieve its signature.
440
- if (!F)
441
- return std::nullopt;
442
- const ElementCount EC = getECFromSignature (F->getFunctionType ());
443
- VF = EC.getKnownMinValue ();
444
- }
445
-
446
- // 1. We don't accept a zero lanes vectorization factor.
447
- // 2. We don't accept the demangling if the vector function is not
448
- // present in the module.
449
- if (VF == 0 )
450
- return std::nullopt;
451
- if (!M.getFunction (VectorName))
452
- return std::nullopt;
453
-
454
- const VFShape Shape ({ElementCount::get (VF, IsScalable), Parameters});
495
+ const VFShape Shape ({*EC, Parameters});
455
496
return VFInfo ({Shape, std::string (ScalarName), std::string (VectorName), ISA});
456
497
}
457
498
0 commit comments