]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/llvm/lib/Analysis/VFABIDemangling.cpp
Merge ^/vendor/clang/dist up to its last change, and resolve conflicts.
[FreeBSD/FreeBSD.git] / contrib / llvm-project / llvm / lib / Analysis / VFABIDemangling.cpp
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/Analysis/VectorUtils.h"
10
11 using namespace llvm;
12
13 namespace {
14 /// Utilities for the Vector Function ABI name parser.
15
16 /// Return types for the parser functions.
17 enum 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.
25 ParseRet tryParseISA(StringRef &MangledName, VFISAKind &ISA) {
26   if (MangledName.empty())
27     return ParseRet::Error;
28
29   ISA = StringSwitch<VFISAKind>(MangledName.take_front(1))
30             .Case("n", VFISAKind::AdvancedSIMD)
31             .Case("s", VFISAKind::SVE)
32             .Case("b", VFISAKind::SSE)
33             .Case("c", VFISAKind::AVX)
34             .Case("d", VFISAKind::AVX2)
35             .Case("e", VFISAKind::AVX512)
36             .Default(VFISAKind::Unknown);
37
38   MangledName = MangledName.drop_front(1);
39
40   return ParseRet::OK;
41 }
42
43 /// Extracts the `<mask>` information from the mangled string, and
44 /// sets `IsMasked` accordingly. The input string `MangledName` is
45 /// left unmodified.
46 ParseRet tryParseMask(StringRef &MangledName, bool &IsMasked) {
47   if (MangledName.consume_front("M")) {
48     IsMasked = true;
49     return ParseRet::OK;
50   }
51
52   if (MangledName.consume_front("N")) {
53     IsMasked = false;
54     return ParseRet::OK;
55   }
56
57   return ParseRet::Error;
58 }
59
60 /// Extract the `<vlen>` information from the mangled string, and
61 /// sets `VF` accordingly. A `<vlen> == "x"` token is interpreted as a scalable
62 /// vector length. On success, the `<vlen>` token is removed from
63 /// the input string `ParseString`.
64 ///
65 ParseRet tryParseVLEN(StringRef &ParseString, unsigned &VF, bool &IsScalable) {
66   if (ParseString.consume_front("x")) {
67     VF = 0;
68     IsScalable = true;
69     return ParseRet::OK;
70   }
71
72   if (ParseString.consumeInteger(10, VF))
73     return ParseRet::Error;
74
75   IsScalable = false;
76   return ParseRet::OK;
77 }
78
79 /// The function looks for the following strings at the beginning of
80 /// the input string `ParseString`:
81 ///
82 ///  <token> <number>
83 ///
84 /// On success, it removes the parsed parameter from `ParseString`,
85 /// sets `PKind` to the correspondent enum value, sets `Pos` to
86 /// <number>, and return success.  On a syntax error, it return a
87 /// parsing error. If nothing is parsed, it returns None.
88 ///
89 /// The function expects <token> to be one of "ls", "Rs", "Us" or
90 /// "Ls".
91 ParseRet tryParseLinearTokenWithRuntimeStep(StringRef &ParseString,
92                                             VFParamKind &PKind, int &Pos,
93                                             const StringRef Token) {
94   if (ParseString.consume_front(Token)) {
95     PKind = VFABI::getVFParamKindFromString(Token);
96     if (ParseString.consumeInteger(10, Pos))
97       return ParseRet::Error;
98     return ParseRet::OK;
99   }
100
101   return ParseRet::None;
102 }
103
104 /// The function looks for the following stringt at the beginning of
105 /// the input string `ParseString`:
106 ///
107 ///  <token> <number>
108 ///
109 /// <token> is one of "ls", "Rs", "Us" or "Ls".
110 ///
111 /// On success, it removes the parsed parameter from `ParseString`,
112 /// sets `PKind` to the correspondent enum value, sets `StepOrPos` to
113 /// <number>, and return success.  On a syntax error, it return a
114 /// parsing error. If nothing is parsed, it returns None.
115 ParseRet tryParseLinearWithRuntimeStep(StringRef &ParseString,
116                                        VFParamKind &PKind, int &StepOrPos) {
117   ParseRet Ret;
118
119   // "ls" <RuntimeStepPos>
120   Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "ls");
121   if (Ret != ParseRet::None)
122     return Ret;
123
124   // "Rs" <RuntimeStepPos>
125   Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Rs");
126   if (Ret != ParseRet::None)
127     return Ret;
128
129   // "Ls" <RuntimeStepPos>
130   Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Ls");
131   if (Ret != ParseRet::None)
132     return Ret;
133
134   // "Us" <RuntimeStepPos>
135   Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Us");
136   if (Ret != ParseRet::None)
137     return Ret;
138
139   return ParseRet::None;
140 }
141
142 /// The function looks for the following strings at the beginning of
143 /// the input string `ParseString`:
144 ///
145 ///  <token> {"n"} <number>
146 ///
147 /// On success, it removes the parsed parameter from `ParseString`,
148 /// sets `PKind` to the correspondent enum value, sets `LinearStep` to
149 /// <number>, and return success.  On a syntax error, it return a
150 /// parsing error. If nothing is parsed, it returns None.
151 ///
152 /// The function expects <token> to be one of "l", "R", "U" or
153 /// "L".
154 ParseRet tryParseCompileTimeLinearToken(StringRef &ParseString,
155                                         VFParamKind &PKind, int &LinearStep,
156                                         const StringRef Token) {
157   if (ParseString.consume_front(Token)) {
158     PKind = VFABI::getVFParamKindFromString(Token);
159     const bool Negate = ParseString.consume_front("n");
160     if (ParseString.consumeInteger(10, LinearStep))
161       LinearStep = 1;
162     if (Negate)
163       LinearStep *= -1;
164     return ParseRet::OK;
165   }
166
167   return ParseRet::None;
168 }
169
170 /// The function looks for the following strings at the beginning of
171 /// the input string `ParseString`:
172 ///
173 /// ["l" | "R" | "U" | "L"] {"n"} <number>
174 ///
175 /// On success, it removes the parsed parameter from `ParseString`,
176 /// sets `PKind` to the correspondent enum value, sets `LinearStep` to
177 /// <number>, and return success.  On a syntax error, it return a
178 /// parsing error. If nothing is parsed, it returns None.
179 ParseRet tryParseLinearWithCompileTimeStep(StringRef &ParseString,
180                                            VFParamKind &PKind, int &StepOrPos) {
181   // "l" {"n"} <CompileTimeStep>
182   if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "l") ==
183       ParseRet::OK)
184     return ParseRet::OK;
185
186   // "R" {"n"} <CompileTimeStep>
187   if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "R") ==
188       ParseRet::OK)
189     return ParseRet::OK;
190
191   // "L" {"n"} <CompileTimeStep>
192   if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "L") ==
193       ParseRet::OK)
194     return ParseRet::OK;
195
196   // "U" {"n"} <CompileTimeStep>
197   if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "U") ==
198       ParseRet::OK)
199     return ParseRet::OK;
200
201   return ParseRet::None;
202 }
203
204 /// The function looks for the following strings at the beginning of
205 /// the input string `ParseString`:
206 ///
207 /// "u" <number>
208 ///
209 /// On success, it removes the parsed parameter from `ParseString`,
210 /// sets `PKind` to the correspondent enum value, sets `Pos` to
211 /// <number>, and return success.  On a syntax error, it return a
212 /// parsing error. If nothing is parsed, it returns None.
213 ParseRet tryParseUniform(StringRef &ParseString, VFParamKind &PKind, int &Pos) {
214   // "u" <Pos>
215   const char *UniformToken = "u";
216   if (ParseString.consume_front(UniformToken)) {
217     PKind = VFABI::getVFParamKindFromString(UniformToken);
218     if (ParseString.consumeInteger(10, Pos))
219       return ParseRet::Error;
220
221     return ParseRet::OK;
222   }
223   return ParseRet::None;
224 }
225
226 /// Looks into the <parameters> part of the mangled name in search
227 /// for valid paramaters at the beginning of the string
228 /// `ParseString`.
229 ///
230 /// On success, it removes the parsed parameter from `ParseString`,
231 /// sets `PKind` to the correspondent enum value, sets `StepOrPos`
232 /// accordingly, and return success.  On a syntax error, it return a
233 /// parsing error. If nothing is parsed, it returns None.
234 ParseRet tryParseParameter(StringRef &ParseString, VFParamKind &PKind,
235                            int &StepOrPos) {
236   if (ParseString.consume_front("v")) {
237     PKind = VFParamKind::Vector;
238     StepOrPos = 0;
239     return ParseRet::OK;
240   }
241
242   const ParseRet HasLinearRuntime =
243       tryParseLinearWithRuntimeStep(ParseString, PKind, StepOrPos);
244   if (HasLinearRuntime != ParseRet::None)
245     return HasLinearRuntime;
246
247   const ParseRet HasLinearCompileTime =
248       tryParseLinearWithCompileTimeStep(ParseString, PKind, StepOrPos);
249   if (HasLinearCompileTime != ParseRet::None)
250     return HasLinearCompileTime;
251
252   const ParseRet HasUniform = tryParseUniform(ParseString, PKind, StepOrPos);
253   if (HasUniform != ParseRet::None)
254     return HasUniform;
255
256   return ParseRet::None;
257 }
258
259 /// Looks into the <parameters> part of the mangled name in search
260 /// of a valid 'aligned' clause. The function should be invoked
261 /// after parsing a parameter via `tryParseParameter`.
262 ///
263 /// On success, it removes the parsed parameter from `ParseString`,
264 /// sets `PKind` to the correspondent enum value, sets `StepOrPos`
265 /// accordingly, and return success.  On a syntax error, it return a
266 /// parsing error. If nothing is parsed, it returns None.
267 ParseRet tryParseAlign(StringRef &ParseString, Align &Alignment) {
268   uint64_t Val;
269   //    "a" <number>
270   if (ParseString.consume_front("a")) {
271     if (ParseString.consumeInteger(10, Val))
272       return ParseRet::Error;
273
274     if (!isPowerOf2_64(Val))
275       return ParseRet::Error;
276
277     Alignment = Align(Val);
278
279     return ParseRet::OK;
280   }
281
282   return ParseRet::None;
283 }
284 } // namespace
285
286 // Format of the ABI name:
287 // _ZGV<isa><mask><vlen><parameters>_<scalarname>[(<redirection>)]
288 Optional<VFInfo> VFABI::tryDemangleForVFABI(StringRef MangledName) {
289   // Assume there is no custom name <redirection>, and therefore the
290   // vector name consists of
291   // _ZGV<isa><mask><vlen><parameters>_<scalarname>.
292   StringRef VectorName = MangledName;
293
294   // Parse the fixed size part of the manled name
295   if (!MangledName.consume_front("_ZGV"))
296     return None;
297
298   // Extract ISA. An unknow ISA is also supported, so we accept all
299   // values.
300   VFISAKind ISA;
301   if (tryParseISA(MangledName, ISA) != ParseRet::OK)
302     return None;
303
304   // Extract <mask>.
305   bool IsMasked;
306   if (tryParseMask(MangledName, IsMasked) != ParseRet::OK)
307     return None;
308
309   // Parse the variable size, starting from <vlen>.
310   unsigned VF;
311   bool IsScalable;
312   if (tryParseVLEN(MangledName, VF, IsScalable) != ParseRet::OK)
313     return None;
314
315   // Parse the <parameters>.
316   ParseRet ParamFound;
317   SmallVector<VFParameter, 8> Parameters;
318   do {
319     const unsigned ParameterPos = Parameters.size();
320     VFParamKind PKind;
321     int StepOrPos;
322     ParamFound = tryParseParameter(MangledName, PKind, StepOrPos);
323
324     // Bail off if there is a parsing error in the parsing of the parameter.
325     if (ParamFound == ParseRet::Error)
326       return None;
327
328     if (ParamFound == ParseRet::OK) {
329       Align Alignment;
330       // Look for the alignment token "a <number>".
331       const ParseRet AlignFound = tryParseAlign(MangledName, Alignment);
332       // Bail off if there is a syntax error in the align token.
333       if (AlignFound == ParseRet::Error)
334         return None;
335
336       // Add the parameter.
337       Parameters.push_back({ParameterPos, PKind, StepOrPos, Alignment});
338     }
339   } while (ParamFound == ParseRet::OK);
340
341   // A valid MangledName mus have at least one valid entry in the
342   // <parameters>.
343   if (Parameters.empty())
344     return None;
345
346   // Check for the <scalarname> and the optional <redirection>, which
347   // are separated from the prefix with "_"
348   if (!MangledName.consume_front("_"))
349     return None;
350
351   // The rest of the string must be in the format:
352   // <scalarname>[(<redirection>)]
353   const StringRef ScalarName =
354       MangledName.take_while([](char In) { return In != '('; });
355
356   if (ScalarName.empty())
357     return None;
358
359   // Reduce MangledName to [(<redirection>)].
360   MangledName = MangledName.ltrim(ScalarName);
361   // Find the optional custom name redirection.
362   if (MangledName.consume_front("(")) {
363     if (!MangledName.consume_back(")"))
364       return None;
365     // Update the vector variant with the one specified by the user.
366     VectorName = MangledName;
367     // If the vector name is missing, bail out.
368     if (VectorName.empty())
369       return None;
370   }
371
372   // When <mask> is "M", we need to add a parameter that is used as
373   // global predicate for the function.
374   if (IsMasked) {
375     const unsigned Pos = Parameters.size();
376     Parameters.push_back({Pos, VFParamKind::GlobalPredicate});
377   }
378
379   // Asserts for parameters of type `VFParamKind::GlobalPredicate`, as
380   // prescribed by the Vector Function ABI specifications supported by
381   // this parser:
382   // 1. Uniqueness.
383   // 2. Must be the last in the parameter list.
384   const auto NGlobalPreds = std::count_if(
385       Parameters.begin(), Parameters.end(), [](const VFParameter PK) {
386         return PK.ParamKind == VFParamKind::GlobalPredicate;
387       });
388   assert(NGlobalPreds < 2 && "Cannot have more than one global predicate.");
389   if (NGlobalPreds)
390     assert(Parameters.back().ParamKind == VFParamKind::GlobalPredicate &&
391            "The global predicate must be the last parameter");
392
393   const VFShape Shape({VF, IsScalable, ISA, Parameters});
394   return VFInfo({Shape, ScalarName, VectorName});
395 }
396
397 VFParamKind VFABI::getVFParamKindFromString(const StringRef Token) {
398   const VFParamKind ParamKind = StringSwitch<VFParamKind>(Token)
399                                     .Case("v", VFParamKind::Vector)
400                                     .Case("l", VFParamKind::OMP_Linear)
401                                     .Case("R", VFParamKind::OMP_LinearRef)
402                                     .Case("L", VFParamKind::OMP_LinearVal)
403                                     .Case("U", VFParamKind::OMP_LinearUVal)
404                                     .Case("ls", VFParamKind::OMP_LinearPos)
405                                     .Case("Ls", VFParamKind::OMP_LinearValPos)
406                                     .Case("Rs", VFParamKind::OMP_LinearRefPos)
407                                     .Case("Us", VFParamKind::OMP_LinearUValPos)
408                                     .Case("u", VFParamKind::OMP_Uniform)
409                                     .Default(VFParamKind::Unknown);
410
411   if (ParamKind != VFParamKind::Unknown)
412     return ParamKind;
413
414   // This function should never be invoked with an invalid input.
415   llvm_unreachable("This fuction should be invoken only on parameters"
416                    " that have a textual representation in the mangled name"
417                    " of the Vector Function ABI");
418 }