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 
9 #include "llvm/ADT/SmallSet.h"
10 #include "llvm/ADT/SmallString.h"
11 #include "llvm/Analysis/VectorUtils.h"
12 
13 using namespace llvm;
14 
15 namespace {
16 /// Utilities for the Vector Function ABI name parser.
17 
18 /// Return types for the parser functions.
19 enum 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.
27 ParseRet tryParseISA(StringRef &MangledName, VFISAKind &ISA) {
28   if (MangledName.empty())
29     return ParseRet::Error;
30 
31   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   }
45 
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.
52 ParseRet 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 ///
71 ParseRet tryParseVLEN(StringRef &ParseString, unsigned &VF, bool &IsScalable) {
72   if (ParseString.consume_front("x")) {
73     // 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`.
76     VF = 0;
77     IsScalable = true;
78     return ParseRet::OK;
79   }
80 
81   if (ParseString.consumeInteger(10, VF))
82     return ParseRet::Error;
83 
84   // The token `0` is invalid for VLEN.
85   if (VF == 0)
86     return ParseRet::Error;
87 
88   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".
104 ParseRet 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.
128 ParseRet 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".
167 ParseRet 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.
192 ParseRet 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.
226 ParseRet 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.
247 ParseRet 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.
280 ParseRet 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 }
297 #ifndef NDEBUG
298 // Verify the assumtion that all vectors in the signature of a vector
299 // function have the same number of elements.
300 bool 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.
323 ElementCount 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 }
335 } // namespace
336 
337 // Format of the ABI name:
338 // _ZGV<isa><mask><vlen><parameters>_<scalarname>[(<redirection>)]
339 Optional<VFInfo> VFABI::tryDemangleForVFABI(StringRef MangledName,
340                                             const Module &M) {
341   const StringRef OriginalName = MangledName;
342   // 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 
394   // A valid MangledName must have at least one valid entry in the
395   // <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 
425   // 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 
430   // 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 
451   // 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 
477   const VFShape Shape({VF, IsScalable, Parameters});
478   return VFInfo({Shape, std::string(ScalarName), std::string(VectorName), ISA});
479 }
480 
481 VFParamKind 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 }
503