LLVM 18.0.0git
VFABIDemangling.cpp
Go to the documentation of this file.
1//===- VFABIDemangling.cpp - Vector Function ABI demangling utilities. ---===//
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
10
11using namespace llvm;
12
13namespace {
14/// Utilities for the Vector Function ABI name parser.
15
16/// Return types for the parser functions.
17enum class ParseRet {
18 OK, // Found.
19 None, // Not found.
20 Error // Syntax error.
21};
22
23/// Extracts the `<isa>` information from the mangled string, and
24/// sets the `ISA` accordingly.
25ParseRet tryParseISA(StringRef &MangledName, VFISAKind &ISA) {
26 if (MangledName.empty())
27 return ParseRet::Error;
28
29 if (MangledName.startswith(VFABI::_LLVM_)) {
30 MangledName = MangledName.drop_front(strlen(VFABI::_LLVM_));
31 ISA = VFISAKind::LLVM;
32 } else {
33 ISA = StringSwitch<VFISAKind>(MangledName.take_front(1))
34 .Case("n", VFISAKind::AdvancedSIMD)
35 .Case("s", VFISAKind::SVE)
36 .Case("b", VFISAKind::SSE)
37 .Case("c", VFISAKind::AVX)
38 .Case("d", VFISAKind::AVX2)
39 .Case("e", VFISAKind::AVX512)
40 .Default(VFISAKind::Unknown);
41 MangledName = MangledName.drop_front(1);
42 }
43
44 return ParseRet::OK;
45}
46
47/// Extracts the `<mask>` information from the mangled string, and
48/// sets `IsMasked` accordingly. The input string `MangledName` is
49/// left unmodified.
50ParseRet tryParseMask(StringRef &MangledName, bool &IsMasked) {
51 if (MangledName.consume_front("M")) {
52 IsMasked = true;
53 return ParseRet::OK;
54 }
55
56 if (MangledName.consume_front("N")) {
57 IsMasked = false;
58 return ParseRet::OK;
59 }
60
61 return ParseRet::Error;
62}
63
64/// 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///
69ParseRet tryParseVLEN(StringRef &ParseString, unsigned &VF, bool &IsScalable) {
70 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;
76 return ParseRet::OK;
77 }
78
79 if (ParseString.consumeInteger(10, VF))
80 return ParseRet::Error;
81
82 // The token `0` is invalid for VLEN.
83 if (VF == 0)
84 return ParseRet::Error;
85
86 IsScalable = false;
87 return ParseRet::OK;
88}
89
90/// The function looks for the following strings at the beginning of
91/// the input string `ParseString`:
92///
93/// <token> <number>
94///
95/// On success, it removes the parsed parameter from `ParseString`,
96/// sets `PKind` to the correspondent enum value, sets `Pos` to
97/// <number>, and return success. On a syntax error, it return a
98/// parsing error. If nothing is parsed, it returns std::nullopt.
99///
100/// The function expects <token> to be one of "ls", "Rs", "Us" or
101/// "Ls".
102ParseRet tryParseLinearTokenWithRuntimeStep(StringRef &ParseString,
103 VFParamKind &PKind, int &Pos,
104 const StringRef Token) {
105 if (ParseString.consume_front(Token)) {
106 PKind = VFABI::getVFParamKindFromString(Token);
107 if (ParseString.consumeInteger(10, Pos))
108 return ParseRet::Error;
109 return ParseRet::OK;
110 }
111
112 return ParseRet::None;
113}
114
115/// The function looks for the following stringt at the beginning of
116/// the input string `ParseString`:
117///
118/// <token> <number>
119///
120/// <token> is one of "ls", "Rs", "Us" or "Ls".
121///
122/// On success, it removes the parsed parameter from `ParseString`,
123/// sets `PKind` to the correspondent enum value, sets `StepOrPos` to
124/// <number>, and return success. On a syntax error, it return a
125/// parsing error. If nothing is parsed, it returns std::nullopt.
126ParseRet tryParseLinearWithRuntimeStep(StringRef &ParseString,
127 VFParamKind &PKind, int &StepOrPos) {
128 ParseRet Ret;
129
130 // "ls" <RuntimeStepPos>
131 Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "ls");
132 if (Ret != ParseRet::None)
133 return Ret;
134
135 // "Rs" <RuntimeStepPos>
136 Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Rs");
137 if (Ret != ParseRet::None)
138 return Ret;
139
140 // "Ls" <RuntimeStepPos>
141 Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Ls");
142 if (Ret != ParseRet::None)
143 return Ret;
144
145 // "Us" <RuntimeStepPos>
146 Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Us");
147 if (Ret != ParseRet::None)
148 return Ret;
149
150 return ParseRet::None;
151}
152
153/// The function looks for the following strings at the beginning of
154/// the input string `ParseString`:
155///
156/// <token> {"n"} <number>
157///
158/// On success, it removes the parsed parameter from `ParseString`,
159/// sets `PKind` to the correspondent enum value, sets `LinearStep` to
160/// <number>, and return success. On a syntax error, it return a
161/// parsing error. If nothing is parsed, it returns std::nullopt.
162///
163/// The function expects <token> to be one of "l", "R", "U" or
164/// "L".
165ParseRet tryParseCompileTimeLinearToken(StringRef &ParseString,
166 VFParamKind &PKind, int &LinearStep,
167 const StringRef Token) {
168 if (ParseString.consume_front(Token)) {
169 PKind = VFABI::getVFParamKindFromString(Token);
170 const bool Negate = ParseString.consume_front("n");
171 if (ParseString.consumeInteger(10, LinearStep))
172 LinearStep = 1;
173 if (Negate)
174 LinearStep *= -1;
175 return ParseRet::OK;
176 }
177
178 return ParseRet::None;
179}
180
181/// The function looks for the following strings at the beginning of
182/// the input string `ParseString`:
183///
184/// ["l" | "R" | "U" | "L"] {"n"} <number>
185///
186/// On success, it removes the parsed parameter from `ParseString`,
187/// sets `PKind` to the correspondent enum value, sets `LinearStep` to
188/// <number>, and return success. On a syntax error, it return a
189/// parsing error. If nothing is parsed, it returns std::nullopt.
190ParseRet tryParseLinearWithCompileTimeStep(StringRef &ParseString,
191 VFParamKind &PKind, int &StepOrPos) {
192 // "l" {"n"} <CompileTimeStep>
193 if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "l") ==
194 ParseRet::OK)
195 return ParseRet::OK;
196
197 // "R" {"n"} <CompileTimeStep>
198 if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "R") ==
199 ParseRet::OK)
200 return ParseRet::OK;
201
202 // "L" {"n"} <CompileTimeStep>
203 if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "L") ==
204 ParseRet::OK)
205 return ParseRet::OK;
206
207 // "U" {"n"} <CompileTimeStep>
208 if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "U") ==
209 ParseRet::OK)
210 return ParseRet::OK;
211
212 return ParseRet::None;
213}
214
215/// Looks into the <parameters> part of the mangled name in search
216/// for valid paramaters at the beginning of the string
217/// `ParseString`.
218///
219/// On success, it removes the parsed parameter from `ParseString`,
220/// sets `PKind` to the correspondent enum value, sets `StepOrPos`
221/// accordingly, and return success. On a syntax error, it return a
222/// parsing error. If nothing is parsed, it returns std::nullopt.
223ParseRet tryParseParameter(StringRef &ParseString, VFParamKind &PKind,
224 int &StepOrPos) {
225 if (ParseString.consume_front("v")) {
226 PKind = VFParamKind::Vector;
227 StepOrPos = 0;
228 return ParseRet::OK;
229 }
230
231 if (ParseString.consume_front("u")) {
232 PKind = VFParamKind::OMP_Uniform;
233 StepOrPos = 0;
234 return ParseRet::OK;
235 }
236
237 const ParseRet HasLinearRuntime =
238 tryParseLinearWithRuntimeStep(ParseString, PKind, StepOrPos);
239 if (HasLinearRuntime != ParseRet::None)
240 return HasLinearRuntime;
241
242 const ParseRet HasLinearCompileTime =
243 tryParseLinearWithCompileTimeStep(ParseString, PKind, StepOrPos);
244 if (HasLinearCompileTime != ParseRet::None)
245 return HasLinearCompileTime;
246
247 return ParseRet::None;
248}
249
250/// Looks into the <parameters> part of the mangled name in search
251/// of a valid 'aligned' clause. The function should be invoked
252/// after parsing a parameter via `tryParseParameter`.
253///
254/// On success, it removes the parsed parameter from `ParseString`,
255/// sets `PKind` to the correspondent enum value, sets `StepOrPos`
256/// accordingly, and return success. On a syntax error, it return a
257/// parsing error. If nothing is parsed, it returns std::nullopt.
258ParseRet tryParseAlign(StringRef &ParseString, Align &Alignment) {
259 uint64_t Val;
260 // "a" <number>
261 if (ParseString.consume_front("a")) {
262 if (ParseString.consumeInteger(10, Val))
263 return ParseRet::Error;
264
265 if (!isPowerOf2_64(Val))
266 return ParseRet::Error;
267
268 Alignment = Align(Val);
269
270 return ParseRet::OK;
271 }
272
273 return ParseRet::None;
274}
275
276#ifndef NDEBUG
277// Verify the assumtion that all vectors in the signature of a vector
278// function have the same number of elements.
279bool verifyAllVectorsHaveSameWidth(FunctionType *Signature) {
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 });
295}
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.
301ElementCount 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);
312}
313} // namespace
314
315// Format of the ABI name:
316// _ZGV<isa><mask><vlen><parameters>_<scalarname>[(<redirection>)]
317std::optional<VFInfo> VFABI::tryDemangleForVFABI(StringRef MangledName,
318 const Module &M) {
319 const StringRef OriginalName = MangledName;
320 // Assume there is no custom name <redirection>, and therefore the
321 // vector name consists of
322 // _ZGV<isa><mask><vlen><parameters>_<scalarname>.
323 StringRef VectorName = MangledName;
324
325 // Parse the fixed size part of the manled name
326 if (!MangledName.consume_front("_ZGV"))
327 return std::nullopt;
328
329 // Extract ISA. An unknow ISA is also supported, so we accept all
330 // values.
331 VFISAKind ISA;
332 if (tryParseISA(MangledName, ISA) != ParseRet::OK)
333 return std::nullopt;
334
335 // Extract <mask>.
336 bool IsMasked;
337 if (tryParseMask(MangledName, IsMasked) != ParseRet::OK)
338 return std::nullopt;
339
340 // Parse the variable size, starting from <vlen>.
341 unsigned VF;
342 bool IsScalable;
343 if (tryParseVLEN(MangledName, VF, IsScalable) != ParseRet::OK)
344 return std::nullopt;
345
346 // Parse the <parameters>.
347 ParseRet ParamFound;
349 do {
350 const unsigned ParameterPos = Parameters.size();
351 VFParamKind PKind;
352 int StepOrPos;
353 ParamFound = tryParseParameter(MangledName, PKind, StepOrPos);
354
355 // Bail off if there is a parsing error in the parsing of the parameter.
356 if (ParamFound == ParseRet::Error)
357 return std::nullopt;
358
359 if (ParamFound == ParseRet::OK) {
360 Align Alignment;
361 // Look for the alignment token "a <number>".
362 const ParseRet AlignFound = tryParseAlign(MangledName, Alignment);
363 // Bail off if there is a syntax error in the align token.
364 if (AlignFound == ParseRet::Error)
365 return std::nullopt;
366
367 // Add the parameter.
368 Parameters.push_back({ParameterPos, PKind, StepOrPos, Alignment});
369 }
370 } while (ParamFound == ParseRet::OK);
371
372 // A valid MangledName must have at least one valid entry in the
373 // <parameters>.
374 if (Parameters.empty())
375 return std::nullopt;
376
377 // Check for the <scalarname> and the optional <redirection>, which
378 // are separated from the prefix with "_"
379 if (!MangledName.consume_front("_"))
380 return std::nullopt;
381
382 // The rest of the string must be in the format:
383 // <scalarname>[(<redirection>)]
384 const StringRef ScalarName =
385 MangledName.take_while([](char In) { return In != '('; });
386
387 if (ScalarName.empty())
388 return std::nullopt;
389
390 // Reduce MangledName to [(<redirection>)].
391 MangledName = MangledName.ltrim(ScalarName);
392 // Find the optional custom name redirection.
393 if (MangledName.consume_front("(")) {
394 if (!MangledName.consume_back(")"))
395 return std::nullopt;
396 // Update the vector variant with the one specified by the user.
397 VectorName = MangledName;
398 // If the vector name is missing, bail out.
399 if (VectorName.empty())
400 return std::nullopt;
401 }
402
403 // LLVM internal mapping via the TargetLibraryInfo (TLI) must be
404 // redirected to an existing name.
405 if (ISA == VFISAKind::LLVM && VectorName == OriginalName)
406 return std::nullopt;
407
408 // When <mask> is "M", we need to add a parameter that is used as
409 // global predicate for the function.
410 if (IsMasked) {
411 const unsigned Pos = Parameters.size();
412 Parameters.push_back({Pos, VFParamKind::GlobalPredicate});
413 }
414
415 // Asserts for parameters of type `VFParamKind::GlobalPredicate`, as
416 // prescribed by the Vector Function ABI specifications supported by
417 // this parser:
418 // 1. Uniqueness.
419 // 2. Must be the last in the parameter list.
420 const auto NGlobalPreds =
421 llvm::count_if(Parameters, [](const VFParameter &PK) {
422 return PK.ParamKind == VFParamKind::GlobalPredicate;
423 });
424 assert(NGlobalPreds < 2 && "Cannot have more than one global predicate.");
425 if (NGlobalPreds)
426 assert(Parameters.back().ParamKind == VFParamKind::GlobalPredicate &&
427 "The global predicate must be the last parameter");
428
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});
455 return VFInfo({Shape, std::string(ScalarName), std::string(VectorName), ISA});
456}
457
459 const VFParamKind ParamKind = StringSwitch<VFParamKind>(Token)
460 .Case("v", VFParamKind::Vector)
461 .Case("l", VFParamKind::OMP_Linear)
462 .Case("R", VFParamKind::OMP_LinearRef)
463 .Case("L", VFParamKind::OMP_LinearVal)
464 .Case("U", VFParamKind::OMP_LinearUVal)
465 .Case("ls", VFParamKind::OMP_LinearPos)
466 .Case("Ls", VFParamKind::OMP_LinearValPos)
467 .Case("Rs", VFParamKind::OMP_LinearRefPos)
468 .Case("Us", VFParamKind::OMP_LinearUValPos)
469 .Case("u", VFParamKind::OMP_Uniform)
470 .Default(VFParamKind::Unknown);
471
472 if (ParamKind != VFParamKind::Unknown)
473 return ParamKind;
474
475 // This function should never be invoked with an invalid input.
476 llvm_unreachable("This fuction should be invoken only on parameters"
477 " that have a textual representation in the mangled name"
478 " of the Vector Function ABI");
479}
return RetTy
#define F(x, y, z)
Definition: MD5.cpp:55
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
@ None
static constexpr ElementCount getFixed(ScalarTy MinVal)
Definition: TypeSize.h:291
static constexpr ElementCount get(ScalarTy MinVal, bool Scalable)
Definition: TypeSize.h:297
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
bool empty() const
Definition: SmallVector.h:94
size_t size() const
Definition: SmallVector.h:91
void push_back(const T &Elt)
Definition: SmallVector.h:416
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
bool consume_back(StringRef Suffix)
Returns true if this StringRef has the given suffix and removes that suffix.
Definition: StringRef.h:659
bool consumeInteger(unsigned Radix, T &Result)
Parse the current string as an integer of the specified radix.
Definition: StringRef.h:503
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:134
StringRef take_while(function_ref< bool(char)> F) const
Return the longest prefix of 'this' such that every character in the prefix satisfies the given predi...
Definition: StringRef.h:601
StringRef drop_front(size_t N=1) const
Return a StringRef equal to 'this' but with the first N elements dropped.
Definition: StringRef.h:613
StringRef ltrim(char Char) const
Return string with consecutive Char characters starting from the the left removed.
Definition: StringRef.h:795
bool startswith(StringRef Prefix) const
Definition: StringRef.h:261
bool consume_front(StringRef Prefix)
Returns true if this StringRef has the given prefix and removes that prefix.
Definition: StringRef.h:639
StringRef take_front(size_t N=1) const
Return a StringRef equal to 'this' but with only the first N elements remaining.
Definition: StringRef.h:584
A switch()-like statement whose cases are string literals.
Definition: StringSwitch.h:44
StringSwitch & Case(StringLiteral S, T Value)
Definition: StringSwitch.h:69
R Default(T Value)
Definition: StringSwitch.h:182
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
std::optional< VFInfo > tryDemangleForVFABI(StringRef MangledName, const Module &M)
Function to construct a VFInfo out of a mangled names in the following format:
VFParamKind getVFParamKindFromString(const StringRef Token)
Retrieve the VFParamKind from a string token.
static constexpr char const * _LLVM_
LLVM Internal VFABI ISA token for vector functions.
Definition: VectorUtils.h:147
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition: STLExtras.h:330
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1727
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Definition: MathExtras.h:269
VFISAKind
Describes the type of Instruction Set Architecture.
Definition: VectorUtils.h:44
auto count_if(R &&Range, UnaryPredicate P)
Wrapper function around std::count_if to count the number of times an element satisfying a given pred...
Definition: STLExtras.h:1926
VFParamKind
Describes the type of Parameters.
Definition: VectorUtils.h:25
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
Holds the VFShape for a specific scalar to vector function mapping.
Definition: VectorUtils.h:123
Encapsulates information needed to describe a parameter.
Definition: VectorUtils.h:62
VFParamKind ParamKind
Definition: VectorUtils.h:64
Contains the information about the kind of vectorization available.
Definition: VectorUtils.h:82