blob: a975e0ff493a96f4bef48cdd9d8d8e1ee9060473 [file] [log] [blame]
Francesco Petrogallicb032aa2019-09-19 17:47:32 +00001//===- 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
Francesco Petrogallie9a06e02019-10-30 19:08:21 +00009#include "llvm/ADT/SmallSet.h"
10#include "llvm/ADT/SmallString.h"
Francesco Petrogallicb032aa2019-09-19 17:47:32 +000011#include "llvm/Analysis/VectorUtils.h"
12
13using namespace llvm;
14
15namespace {
16/// Utilities for the Vector Function ABI name parser.
17
18/// Return types for the parser functions.
19enum class ParseRet {
20 OK, // Found.
21 None, // Not found.
22 Error // Syntax error.
23};
24
25/// Extracts the `<isa>` information from the mangled string, and
26/// sets the `ISA` accordingly.
27ParseRet tryParseISA(StringRef &MangledName, VFISAKind &ISA) {
28 if (MangledName.empty())
29 return ParseRet::Error;
30
Francesco Petrogallid8b6b112019-11-11 16:48:51 +000031 if (MangledName.startswith(VFABI::_LLVM_)) {
32 MangledName = MangledName.drop_front(strlen(VFABI::_LLVM_));
33 ISA = VFISAKind::LLVM;
34 } else {
35 ISA = StringSwitch<VFISAKind>(MangledName.take_front(1))
36 .Case("n", VFISAKind::AdvancedSIMD)
37 .Case("s", VFISAKind::SVE)
38 .Case("b", VFISAKind::SSE)
39 .Case("c", VFISAKind::AVX)
40 .Case("d", VFISAKind::AVX2)
41 .Case("e", VFISAKind::AVX512)
42 .Default(VFISAKind::Unknown);
43 MangledName = MangledName.drop_front(1);
44 }
Francesco Petrogallicb032aa2019-09-19 17:47:32 +000045
46 return ParseRet::OK;
47}
48
49/// Extracts the `<mask>` information from the mangled string, and
50/// sets `IsMasked` accordingly. The input string `MangledName` is
51/// left unmodified.
52ParseRet tryParseMask(StringRef &MangledName, bool &IsMasked) {
53 if (MangledName.consume_front("M")) {
54 IsMasked = true;
55 return ParseRet::OK;
56 }
57
58 if (MangledName.consume_front("N")) {
59 IsMasked = false;
60 return ParseRet::OK;
61 }
62
63 return ParseRet::Error;
64}
65
66/// Extract the `<vlen>` information from the mangled string, and
67/// sets `VF` accordingly. A `<vlen> == "x"` token is interpreted as a scalable
68/// vector length. On success, the `<vlen>` token is removed from
69/// the input string `ParseString`.
70///
71ParseRet tryParseVLEN(StringRef &ParseString, unsigned &VF, bool &IsScalable) {
72 if (ParseString.consume_front("x")) {
Francesco Petrogalli623cff82020-01-22 22:34:27 +000073 // Set VF to 0, to be later adjusted to a value grater than zero
74 // by looking at the signature of the vector function with
75 // `getECFromSignature`.
Francesco Petrogallicb032aa2019-09-19 17:47:32 +000076 VF = 0;
77 IsScalable = true;
78 return ParseRet::OK;
79 }
80
81 if (ParseString.consumeInteger(10, VF))
82 return ParseRet::Error;
83
Francesco Petrogalli623cff82020-01-22 22:34:27 +000084 // The token `0` is invalid for VLEN.
85 if (VF == 0)
86 return ParseRet::Error;
87
Francesco Petrogallicb032aa2019-09-19 17:47:32 +000088 IsScalable = false;
89 return ParseRet::OK;
90}
91
92/// The function looks for the following strings at the beginning of
93/// the input string `ParseString`:
94///
95/// <token> <number>
96///
97/// On success, it removes the parsed parameter from `ParseString`,
98/// sets `PKind` to the correspondent enum value, sets `Pos` to
99/// <number>, and return success. On a syntax error, it return a
100/// parsing error. If nothing is parsed, it returns None.
101///
102/// The function expects <token> to be one of "ls", "Rs", "Us" or
103/// "Ls".
104ParseRet tryParseLinearTokenWithRuntimeStep(StringRef &ParseString,
105 VFParamKind &PKind, int &Pos,
106 const StringRef Token) {
107 if (ParseString.consume_front(Token)) {
108 PKind = VFABI::getVFParamKindFromString(Token);
109 if (ParseString.consumeInteger(10, Pos))
110 return ParseRet::Error;
111 return ParseRet::OK;
112 }
113
114 return ParseRet::None;
115}
116
117/// The function looks for the following stringt at the beginning of
118/// the input string `ParseString`:
119///
120/// <token> <number>
121///
122/// <token> is one of "ls", "Rs", "Us" or "Ls".
123///
124/// On success, it removes the parsed parameter from `ParseString`,
125/// sets `PKind` to the correspondent enum value, sets `StepOrPos` to
126/// <number>, and return success. On a syntax error, it return a
127/// parsing error. If nothing is parsed, it returns None.
128ParseRet tryParseLinearWithRuntimeStep(StringRef &ParseString,
129 VFParamKind &PKind, int &StepOrPos) {
130 ParseRet Ret;
131
132 // "ls" <RuntimeStepPos>
133 Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "ls");
134 if (Ret != ParseRet::None)
135 return Ret;
136
137 // "Rs" <RuntimeStepPos>
138 Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Rs");
139 if (Ret != ParseRet::None)
140 return Ret;
141
142 // "Ls" <RuntimeStepPos>
143 Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Ls");
144 if (Ret != ParseRet::None)
145 return Ret;
146
147 // "Us" <RuntimeStepPos>
148 Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Us");
149 if (Ret != ParseRet::None)
150 return Ret;
151
152 return ParseRet::None;
153}
154
155/// The function looks for the following strings at the beginning of
156/// the input string `ParseString`:
157///
158/// <token> {"n"} <number>
159///
160/// On success, it removes the parsed parameter from `ParseString`,
161/// sets `PKind` to the correspondent enum value, sets `LinearStep` to
162/// <number>, and return success. On a syntax error, it return a
163/// parsing error. If nothing is parsed, it returns None.
164///
165/// The function expects <token> to be one of "l", "R", "U" or
166/// "L".
167ParseRet tryParseCompileTimeLinearToken(StringRef &ParseString,
168 VFParamKind &PKind, int &LinearStep,
169 const StringRef Token) {
170 if (ParseString.consume_front(Token)) {
171 PKind = VFABI::getVFParamKindFromString(Token);
172 const bool Negate = ParseString.consume_front("n");
173 if (ParseString.consumeInteger(10, LinearStep))
174 LinearStep = 1;
175 if (Negate)
176 LinearStep *= -1;
177 return ParseRet::OK;
178 }
179
180 return ParseRet::None;
181}
182
183/// The function looks for the following strings at the beginning of
184/// the input string `ParseString`:
185///
186/// ["l" | "R" | "U" | "L"] {"n"} <number>
187///
188/// On success, it removes the parsed parameter from `ParseString`,
189/// sets `PKind` to the correspondent enum value, sets `LinearStep` to
190/// <number>, and return success. On a syntax error, it return a
191/// parsing error. If nothing is parsed, it returns None.
192ParseRet tryParseLinearWithCompileTimeStep(StringRef &ParseString,
193 VFParamKind &PKind, int &StepOrPos) {
194 // "l" {"n"} <CompileTimeStep>
195 if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "l") ==
196 ParseRet::OK)
197 return ParseRet::OK;
198
199 // "R" {"n"} <CompileTimeStep>
200 if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "R") ==
201 ParseRet::OK)
202 return ParseRet::OK;
203
204 // "L" {"n"} <CompileTimeStep>
205 if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "L") ==
206 ParseRet::OK)
207 return ParseRet::OK;
208
209 // "U" {"n"} <CompileTimeStep>
210 if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "U") ==
211 ParseRet::OK)
212 return ParseRet::OK;
213
214 return ParseRet::None;
215}
216
217/// The function looks for the following strings at the beginning of
218/// the input string `ParseString`:
219///
220/// "u" <number>
221///
222/// On success, it removes the parsed parameter from `ParseString`,
223/// sets `PKind` to the correspondent enum value, sets `Pos` to
224/// <number>, and return success. On a syntax error, it return a
225/// parsing error. If nothing is parsed, it returns None.
226ParseRet tryParseUniform(StringRef &ParseString, VFParamKind &PKind, int &Pos) {
227 // "u" <Pos>
228 const char *UniformToken = "u";
229 if (ParseString.consume_front(UniformToken)) {
230 PKind = VFABI::getVFParamKindFromString(UniformToken);
231 if (ParseString.consumeInteger(10, Pos))
232 return ParseRet::Error;
233
234 return ParseRet::OK;
235 }
236 return ParseRet::None;
237}
238
239/// Looks into the <parameters> part of the mangled name in search
240/// for valid paramaters at the beginning of the string
241/// `ParseString`.
242///
243/// On success, it removes the parsed parameter from `ParseString`,
244/// sets `PKind` to the correspondent enum value, sets `StepOrPos`
245/// accordingly, and return success. On a syntax error, it return a
246/// parsing error. If nothing is parsed, it returns None.
247ParseRet tryParseParameter(StringRef &ParseString, VFParamKind &PKind,
248 int &StepOrPos) {
249 if (ParseString.consume_front("v")) {
250 PKind = VFParamKind::Vector;
251 StepOrPos = 0;
252 return ParseRet::OK;
253 }
254
255 const ParseRet HasLinearRuntime =
256 tryParseLinearWithRuntimeStep(ParseString, PKind, StepOrPos);
257 if (HasLinearRuntime != ParseRet::None)
258 return HasLinearRuntime;
259
260 const ParseRet HasLinearCompileTime =
261 tryParseLinearWithCompileTimeStep(ParseString, PKind, StepOrPos);
262 if (HasLinearCompileTime != ParseRet::None)
263 return HasLinearCompileTime;
264
265 const ParseRet HasUniform = tryParseUniform(ParseString, PKind, StepOrPos);
266 if (HasUniform != ParseRet::None)
267 return HasUniform;
268
269 return ParseRet::None;
270}
271
272/// Looks into the <parameters> part of the mangled name in search
273/// of a valid 'aligned' clause. The function should be invoked
274/// after parsing a parameter via `tryParseParameter`.
275///
276/// On success, it removes the parsed parameter from `ParseString`,
277/// sets `PKind` to the correspondent enum value, sets `StepOrPos`
278/// accordingly, and return success. On a syntax error, it return a
279/// parsing error. If nothing is parsed, it returns None.
280ParseRet tryParseAlign(StringRef &ParseString, Align &Alignment) {
281 uint64_t Val;
282 // "a" <number>
283 if (ParseString.consume_front("a")) {
284 if (ParseString.consumeInteger(10, Val))
285 return ParseRet::Error;
286
287 if (!isPowerOf2_64(Val))
288 return ParseRet::Error;
289
290 Alignment = Align(Val);
291
292 return ParseRet::OK;
293 }
294
295 return ParseRet::None;
296}
Francesco Petrogalli623cff82020-01-22 22:34:27 +0000297#ifndef NDEBUG
298// Verify the assumtion that all vectors in the signature of a vector
299// function have the same number of elements.
300bool verifyAllVectorsHaveSameWidth(FunctionType *Signature) {
301 SmallVector<VectorType *, 2> VecTys;
302 if (auto *RetTy = dyn_cast<VectorType>(Signature->getReturnType()))
303 VecTys.push_back(RetTy);
304 for (auto *Ty : Signature->params())
305 if (auto *VTy = dyn_cast<VectorType>(Ty))
306 VecTys.push_back(VTy);
307
308 if (VecTys.size() <= 1)
309 return true;
310
311 assert(VecTys.size() > 1 && "Invalid number of elements.");
312 const ElementCount EC = VecTys[0]->getElementCount();
313 return llvm::all_of(
314 llvm::make_range(VecTys.begin() + 1, VecTys.end()),
315 [&EC](VectorType *VTy) { return (EC == VTy->getElementCount()); });
316}
317
318#endif // NDEBUG
319
320// Extract the VectorizationFactor from a given function signature,
321// under the assumtion that all vectors have the same number of
322// elements, i.e. same ElementCount.Min.
323ElementCount getECFromSignature(FunctionType *Signature) {
324 assert(verifyAllVectorsHaveSameWidth(Signature) &&
325 "Invalid vector signature.");
326
327 if (auto *RetTy = dyn_cast<VectorType>(Signature->getReturnType()))
328 return RetTy->getElementCount();
329 for (auto *Ty : Signature->params())
330 if (auto *VTy = dyn_cast<VectorType>(Ty))
331 return VTy->getElementCount();
332
333 return ElementCount(/*Min=*/1, /*Scalable=*/false);
334}
Francesco Petrogallicb032aa2019-09-19 17:47:32 +0000335} // namespace
336
337// Format of the ABI name:
338// _ZGV<isa><mask><vlen><parameters>_<scalarname>[(<redirection>)]
Francesco Petrogalli623cff82020-01-22 22:34:27 +0000339Optional<VFInfo> VFABI::tryDemangleForVFABI(StringRef MangledName,
340 const Module &M) {
Francesco Petrogallid8b6b112019-11-11 16:48:51 +0000341 const StringRef OriginalName = MangledName;
Francesco Petrogallicb032aa2019-09-19 17:47:32 +0000342 // Assume there is no custom name <redirection>, and therefore the
343 // vector name consists of
344 // _ZGV<isa><mask><vlen><parameters>_<scalarname>.
345 StringRef VectorName = MangledName;
346
347 // Parse the fixed size part of the manled name
348 if (!MangledName.consume_front("_ZGV"))
349 return None;
350
351 // Extract ISA. An unknow ISA is also supported, so we accept all
352 // values.
353 VFISAKind ISA;
354 if (tryParseISA(MangledName, ISA) != ParseRet::OK)
355 return None;
356
357 // Extract <mask>.
358 bool IsMasked;
359 if (tryParseMask(MangledName, IsMasked) != ParseRet::OK)
360 return None;
361
362 // Parse the variable size, starting from <vlen>.
363 unsigned VF;
364 bool IsScalable;
365 if (tryParseVLEN(MangledName, VF, IsScalable) != ParseRet::OK)
366 return None;
367
368 // Parse the <parameters>.
369 ParseRet ParamFound;
370 SmallVector<VFParameter, 8> Parameters;
371 do {
372 const unsigned ParameterPos = Parameters.size();
373 VFParamKind PKind;
374 int StepOrPos;
375 ParamFound = tryParseParameter(MangledName, PKind, StepOrPos);
376
377 // Bail off if there is a parsing error in the parsing of the parameter.
378 if (ParamFound == ParseRet::Error)
379 return None;
380
381 if (ParamFound == ParseRet::OK) {
382 Align Alignment;
383 // Look for the alignment token "a <number>".
384 const ParseRet AlignFound = tryParseAlign(MangledName, Alignment);
385 // Bail off if there is a syntax error in the align token.
386 if (AlignFound == ParseRet::Error)
387 return None;
388
389 // Add the parameter.
390 Parameters.push_back({ParameterPos, PKind, StepOrPos, Alignment});
391 }
392 } while (ParamFound == ParseRet::OK);
393
Francesco Petrogallie9a06e02019-10-30 19:08:21 +0000394 // A valid MangledName must have at least one valid entry in the
Francesco Petrogallicb032aa2019-09-19 17:47:32 +0000395 // <parameters>.
396 if (Parameters.empty())
397 return None;
398
399 // Check for the <scalarname> and the optional <redirection>, which
400 // are separated from the prefix with "_"
401 if (!MangledName.consume_front("_"))
402 return None;
403
404 // The rest of the string must be in the format:
405 // <scalarname>[(<redirection>)]
406 const StringRef ScalarName =
407 MangledName.take_while([](char In) { return In != '('; });
408
409 if (ScalarName.empty())
410 return None;
411
412 // Reduce MangledName to [(<redirection>)].
413 MangledName = MangledName.ltrim(ScalarName);
414 // Find the optional custom name redirection.
415 if (MangledName.consume_front("(")) {
416 if (!MangledName.consume_back(")"))
417 return None;
418 // Update the vector variant with the one specified by the user.
419 VectorName = MangledName;
420 // If the vector name is missing, bail out.
421 if (VectorName.empty())
422 return None;
423 }
424
Francesco Petrogallid8b6b112019-11-11 16:48:51 +0000425 // LLVM internal mapping via the TargetLibraryInfo (TLI) must be
426 // redirected to an existing name.
427 if (ISA == VFISAKind::LLVM && VectorName == OriginalName)
428 return None;
429
Francesco Petrogallicb032aa2019-09-19 17:47:32 +0000430 // When <mask> is "M", we need to add a parameter that is used as
431 // global predicate for the function.
432 if (IsMasked) {
433 const unsigned Pos = Parameters.size();
434 Parameters.push_back({Pos, VFParamKind::GlobalPredicate});
435 }
436
437 // Asserts for parameters of type `VFParamKind::GlobalPredicate`, as
438 // prescribed by the Vector Function ABI specifications supported by
439 // this parser:
440 // 1. Uniqueness.
441 // 2. Must be the last in the parameter list.
442 const auto NGlobalPreds = std::count_if(
443 Parameters.begin(), Parameters.end(), [](const VFParameter PK) {
444 return PK.ParamKind == VFParamKind::GlobalPredicate;
445 });
446 assert(NGlobalPreds < 2 && "Cannot have more than one global predicate.");
447 if (NGlobalPreds)
448 assert(Parameters.back().ParamKind == VFParamKind::GlobalPredicate &&
449 "The global predicate must be the last parameter");
450
Francesco Petrogalli623cff82020-01-22 22:34:27 +0000451 // Adjust the VF for scalable signatures. The EC.Min is not encoded
452 // in the name of the function, but it is encoded in the IR
453 // signature of the function. We need to extract this information
454 // because it is needed by the loop vectorizer, which reasons in
455 // terms of VectorizationFactor or ElementCount. In particular, we
456 // need to make sure that the VF field of the VFShape class is never
457 // set to 0.
458 if (IsScalable) {
459 const Function *F = M.getFunction(VectorName);
460 // The declaration of the function must be present in the module
461 // to be able to retrieve its signature.
462 if (!F)
463 return None;
464 const ElementCount EC = getECFromSignature(F->getFunctionType());
465 VF = EC.Min;
466 }
467
468 // Sanity checks.
469 // 1. We don't accept a zero lanes vectorization factor.
470 // 2. We don't accept the demangling if the vector function is not
471 // present in the module.
472 if (VF == 0)
473 return None;
474 if (!M.getFunction(VectorName))
475 return None;
476
Francesco Petrogallieac93752019-11-20 20:51:24 +0000477 const VFShape Shape({VF, IsScalable, Parameters});
Benjamin Krameradcd0262020-01-28 20:23:46 +0100478 return VFInfo({Shape, std::string(ScalarName), std::string(VectorName), ISA});
Francesco Petrogallicb032aa2019-09-19 17:47:32 +0000479}
480
481VFParamKind VFABI::getVFParamKindFromString(const StringRef Token) {
482 const VFParamKind ParamKind = StringSwitch<VFParamKind>(Token)
483 .Case("v", VFParamKind::Vector)
484 .Case("l", VFParamKind::OMP_Linear)
485 .Case("R", VFParamKind::OMP_LinearRef)
486 .Case("L", VFParamKind::OMP_LinearVal)
487 .Case("U", VFParamKind::OMP_LinearUVal)
488 .Case("ls", VFParamKind::OMP_LinearPos)
489 .Case("Ls", VFParamKind::OMP_LinearValPos)
490 .Case("Rs", VFParamKind::OMP_LinearRefPos)
491 .Case("Us", VFParamKind::OMP_LinearUValPos)
492 .Case("u", VFParamKind::OMP_Uniform)
493 .Default(VFParamKind::Unknown);
494
495 if (ParamKind != VFParamKind::Unknown)
496 return ParamKind;
497
498 // This function should never be invoked with an invalid input.
499 llvm_unreachable("This fuction should be invoken only on parameters"
500 " that have a textual representation in the mangled name"
501 " of the Vector Function ABI");
502}