/src/llvm-project/llvm/lib/Analysis/VFABIDemangling.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | #include "llvm/Support/Debug.h" |
11 | | #include "llvm/Support/raw_ostream.h" |
12 | | #include <limits> |
13 | | |
14 | | using namespace llvm; |
15 | | |
16 | | #define DEBUG_TYPE "vfabi-demangling" |
17 | | |
18 | | namespace { |
19 | | /// Utilities for the Vector Function ABI name parser. |
20 | | |
21 | | /// Return types for the parser functions. |
22 | | enum class ParseRet { |
23 | | OK, // Found. |
24 | | None, // Not found. |
25 | | Error // Syntax error. |
26 | | }; |
27 | | |
28 | | /// Extracts the `<isa>` information from the mangled string, and |
29 | | /// sets the `ISA` accordingly. If successful, the <isa> token is removed |
30 | | /// from the input string `MangledName`. |
31 | 2.23k | static ParseRet tryParseISA(StringRef &MangledName, VFISAKind &ISA) { |
32 | 2.23k | if (MangledName.empty()) |
33 | 1 | return ParseRet::Error; |
34 | | |
35 | 2.23k | if (MangledName.starts_with(VFABI::_LLVM_)) { |
36 | 435 | MangledName = MangledName.drop_front(strlen(VFABI::_LLVM_)); |
37 | 435 | ISA = VFISAKind::LLVM; |
38 | 1.79k | } else { |
39 | 1.79k | ISA = StringSwitch<VFISAKind>(MangledName.take_front(1)) |
40 | 1.79k | .Case("n", VFISAKind::AdvancedSIMD) |
41 | 1.79k | .Case("s", VFISAKind::SVE) |
42 | 1.79k | .Case("b", VFISAKind::SSE) |
43 | 1.79k | .Case("c", VFISAKind::AVX) |
44 | 1.79k | .Case("d", VFISAKind::AVX2) |
45 | 1.79k | .Case("e", VFISAKind::AVX512) |
46 | 1.79k | .Default(VFISAKind::Unknown); |
47 | 1.79k | MangledName = MangledName.drop_front(1); |
48 | 1.79k | } |
49 | | |
50 | 2.23k | return ParseRet::OK; |
51 | 2.23k | } |
52 | | |
53 | | /// Extracts the `<mask>` information from the mangled string, and |
54 | | /// sets `IsMasked` accordingly. If successful, the <mask> token is removed |
55 | | /// from the input string `MangledName`. |
56 | 2.23k | static ParseRet tryParseMask(StringRef &MangledName, bool &IsMasked) { |
57 | 2.23k | if (MangledName.consume_front("M")) { |
58 | 834 | IsMasked = true; |
59 | 834 | return ParseRet::OK; |
60 | 834 | } |
61 | | |
62 | 1.40k | if (MangledName.consume_front("N")) { |
63 | 1.33k | IsMasked = false; |
64 | 1.33k | return ParseRet::OK; |
65 | 1.33k | } |
66 | | |
67 | 66 | return ParseRet::Error; |
68 | 1.40k | } |
69 | | |
70 | | /// Extract the `<vlen>` information from the mangled string, and |
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 | 2.16k | std::pair<unsigned, bool> &ParsedVF) { |
77 | 2.16k | if (ParseString.consume_front("x")) { |
78 | | // SVE is the only scalable ISA currently supported. |
79 | 178 | if (ISA != VFISAKind::SVE) { |
80 | 13 | LLVM_DEBUG(dbgs() << "Vector function variant declared with scalable VF " |
81 | 13 | << "but ISA is not SVE\n"); |
82 | 13 | return ParseRet::Error; |
83 | 13 | } |
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 | 165 | ParsedVF = {0, true}; |
89 | 165 | return ParseRet::OK; |
90 | 178 | } |
91 | | |
92 | 1.99k | unsigned VF = 0; |
93 | 1.99k | if (ParseString.consumeInteger(10, VF)) |
94 | 135 | return ParseRet::Error; |
95 | | |
96 | | // The token `0` is invalid for VLEN. |
97 | 1.85k | if (VF == 0) |
98 | 4 | return ParseRet::Error; |
99 | | |
100 | 1.85k | ParsedVF = {VF, false}; |
101 | 1.85k | return ParseRet::OK; |
102 | 1.85k | } |
103 | | |
104 | | /// The function looks for the following strings at the beginning of |
105 | | /// the input string `ParseString`: |
106 | | /// |
107 | | /// <token> <number> |
108 | | /// |
109 | | /// On success, it removes the parsed parameter from `ParseString`, |
110 | | /// sets `PKind` to the correspondent enum value, sets `Pos` to |
111 | | /// <number>, and return success. On a syntax error, it return a |
112 | | /// parsing error. If nothing is parsed, it returns std::nullopt. |
113 | | /// |
114 | | /// The function expects <token> to be one of "ls", "Rs", "Us" or |
115 | | /// "Ls". |
116 | | static ParseRet tryParseLinearTokenWithRuntimeStep(StringRef &ParseString, |
117 | | VFParamKind &PKind, int &Pos, |
118 | 21.7M | const StringRef Token) { |
119 | 21.7M | if (ParseString.consume_front(Token)) { |
120 | 3.21k | PKind = VFABI::getVFParamKindFromString(Token); |
121 | 3.21k | if (ParseString.consumeInteger(10, Pos)) |
122 | 277 | return ParseRet::Error; |
123 | 2.93k | return ParseRet::OK; |
124 | 3.21k | } |
125 | | |
126 | 21.7M | return ParseRet::None; |
127 | 21.7M | } |
128 | | |
129 | | /// The function looks for the following string at the beginning of |
130 | | /// the input string `ParseString`: |
131 | | /// |
132 | | /// <token> <number> |
133 | | /// |
134 | | /// <token> is one of "ls", "Rs", "Us" or "Ls". |
135 | | /// |
136 | | /// On success, it removes the parsed parameter from `ParseString`, |
137 | | /// sets `PKind` to the correspondent enum value, sets `StepOrPos` to |
138 | | /// <number>, and return success. On a syntax error, it return a |
139 | | /// parsing error. If nothing is parsed, it returns std::nullopt. |
140 | | static ParseRet tryParseLinearWithRuntimeStep(StringRef &ParseString, |
141 | | VFParamKind &PKind, |
142 | 5.45M | int &StepOrPos) { |
143 | 5.45M | ParseRet Ret; |
144 | | |
145 | | // "ls" <RuntimeStepPos> |
146 | 5.45M | Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "ls"); |
147 | 5.45M | if (Ret != ParseRet::None) |
148 | 398 | return Ret; |
149 | | |
150 | | // "Rs" <RuntimeStepPos> |
151 | 5.45M | Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Rs"); |
152 | 5.45M | if (Ret != ParseRet::None) |
153 | 403 | return Ret; |
154 | | |
155 | | // "Ls" <RuntimeStepPos> |
156 | 5.44M | Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Ls"); |
157 | 5.44M | if (Ret != ParseRet::None) |
158 | 2.00k | return Ret; |
159 | | |
160 | | // "Us" <RuntimeStepPos> |
161 | 5.44M | Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Us"); |
162 | 5.44M | if (Ret != ParseRet::None) |
163 | 408 | return Ret; |
164 | | |
165 | 5.44M | return ParseRet::None; |
166 | 5.44M | } |
167 | | |
168 | | /// The function looks for the following strings at the beginning of |
169 | | /// the input string `ParseString`: |
170 | | /// |
171 | | /// <token> {"n"} <number> |
172 | | /// |
173 | | /// On success, it removes the parsed parameter from `ParseString`, |
174 | | /// sets `PKind` to the correspondent enum value, sets `LinearStep` to |
175 | | /// <number>, and return success. On a syntax error, it return a |
176 | | /// parsing error. If nothing is parsed, it returns std::nullopt. |
177 | | /// |
178 | | /// The function expects <token> to be one of "l", "R", "U" or |
179 | | /// "L". |
180 | | static ParseRet tryParseCompileTimeLinearToken(StringRef &ParseString, |
181 | | VFParamKind &PKind, |
182 | | int &LinearStep, |
183 | 17.1M | const StringRef Token) { |
184 | 17.1M | if (ParseString.consume_front(Token)) { |
185 | 5.44M | PKind = VFABI::getVFParamKindFromString(Token); |
186 | 5.44M | const bool Negate = ParseString.consume_front("n"); |
187 | 5.44M | if (ParseString.consumeInteger(10, LinearStep)) |
188 | 5.44M | LinearStep = 1; |
189 | 5.44M | if (Negate) |
190 | 313 | LinearStep *= -1; |
191 | 5.44M | return ParseRet::OK; |
192 | 5.44M | } |
193 | | |
194 | 11.7M | return ParseRet::None; |
195 | 17.1M | } |
196 | | |
197 | | /// The function looks for the following strings at the beginning of |
198 | | /// the input string `ParseString`: |
199 | | /// |
200 | | /// ["l" | "R" | "U" | "L"] {"n"} <number> |
201 | | /// |
202 | | /// On success, it removes the parsed parameter from `ParseString`, |
203 | | /// sets `PKind` to the correspondent enum value, sets `LinearStep` to |
204 | | /// <number>, and return success. On a syntax error, it return a |
205 | | /// parsing error. If nothing is parsed, it returns std::nullopt. |
206 | | static ParseRet tryParseLinearWithCompileTimeStep(StringRef &ParseString, |
207 | | VFParamKind &PKind, |
208 | 5.44M | int &StepOrPos) { |
209 | | // "l" {"n"} <CompileTimeStep> |
210 | 5.44M | if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "l") == |
211 | 5.44M | ParseRet::OK) |
212 | 109k | return ParseRet::OK; |
213 | | |
214 | | // "R" {"n"} <CompileTimeStep> |
215 | 5.33M | if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "R") == |
216 | 5.33M | ParseRet::OK) |
217 | 37.8k | return ParseRet::OK; |
218 | | |
219 | | // "L" {"n"} <CompileTimeStep> |
220 | 5.30M | if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "L") == |
221 | 5.30M | ParseRet::OK) |
222 | 4.19M | return ParseRet::OK; |
223 | | |
224 | | // "U" {"n"} <CompileTimeStep> |
225 | 1.10M | if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "U") == |
226 | 1.10M | ParseRet::OK) |
227 | 1.10M | return ParseRet::OK; |
228 | | |
229 | 1.58k | return ParseRet::None; |
230 | 1.10M | } |
231 | | |
232 | | /// Looks into the <parameters> part of the mangled name in search |
233 | | /// for valid paramaters at the beginning of the string |
234 | | /// `ParseString`. |
235 | | /// |
236 | | /// On success, it removes the parsed parameter from `ParseString`, |
237 | | /// sets `PKind` to the correspondent enum value, sets `StepOrPos` |
238 | | /// accordingly, and return success. On a syntax error, it return a |
239 | | /// parsing error. If nothing is parsed, it returns std::nullopt. |
240 | | static ParseRet tryParseParameter(StringRef &ParseString, VFParamKind &PKind, |
241 | 7.45M | int &StepOrPos) { |
242 | 7.45M | if (ParseString.consume_front("v")) { |
243 | 1.35M | PKind = VFParamKind::Vector; |
244 | 1.35M | StepOrPos = 0; |
245 | 1.35M | return ParseRet::OK; |
246 | 1.35M | } |
247 | | |
248 | 6.10M | if (ParseString.consume_front("u")) { |
249 | 650k | PKind = VFParamKind::OMP_Uniform; |
250 | 650k | StepOrPos = 0; |
251 | 650k | return ParseRet::OK; |
252 | 650k | } |
253 | | |
254 | 5.45M | const ParseRet HasLinearRuntime = |
255 | 5.45M | tryParseLinearWithRuntimeStep(ParseString, PKind, StepOrPos); |
256 | 5.45M | if (HasLinearRuntime != ParseRet::None) |
257 | 3.21k | return HasLinearRuntime; |
258 | | |
259 | 5.44M | const ParseRet HasLinearCompileTime = |
260 | 5.44M | tryParseLinearWithCompileTimeStep(ParseString, PKind, StepOrPos); |
261 | 5.44M | if (HasLinearCompileTime != ParseRet::None) |
262 | 5.44M | return HasLinearCompileTime; |
263 | | |
264 | 1.58k | return ParseRet::None; |
265 | 5.44M | } |
266 | | |
267 | | /// Looks into the <parameters> part of the mangled name in search |
268 | | /// of a valid 'aligned' clause. The function should be invoked |
269 | | /// after parsing a parameter via `tryParseParameter`. |
270 | | /// |
271 | | /// On success, it removes the parsed parameter from `ParseString`, |
272 | | /// sets `PKind` to the correspondent enum value, sets `StepOrPos` |
273 | | /// accordingly, and return success. On a syntax error, it return a |
274 | | /// parsing error. If nothing is parsed, it returns std::nullopt. |
275 | 7.45M | static ParseRet tryParseAlign(StringRef &ParseString, Align &Alignment) { |
276 | 7.45M | uint64_t Val; |
277 | | // "a" <number> |
278 | 7.45M | if (ParseString.consume_front("a")) { |
279 | 1.02k | if (ParseString.consumeInteger(10, Val)) |
280 | 23 | return ParseRet::Error; |
281 | | |
282 | 1.00k | if (!isPowerOf2_64(Val)) |
283 | 128 | return ParseRet::Error; |
284 | | |
285 | 873 | Alignment = Align(Val); |
286 | | |
287 | 873 | return ParseRet::OK; |
288 | 1.00k | } |
289 | | |
290 | 7.44M | return ParseRet::None; |
291 | 7.45M | } |
292 | | |
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 | 0 | const Type *Ty) { |
301 | | // Only AArch64 SVE is supported at present. |
302 | 0 | assert(ISA == VFISAKind::SVE && |
303 | 0 | "Scalable VF decoding only implemented for SVE\n"); |
304 | | |
305 | 0 | if (Ty->isIntegerTy(64) || Ty->isDoubleTy() || Ty->isPointerTy()) |
306 | 0 | return ElementCount::getScalable(2); |
307 | 0 | if (Ty->isIntegerTy(32) || Ty->isFloatTy()) |
308 | 0 | return ElementCount::getScalable(4); |
309 | 0 | if (Ty->isIntegerTy(16) || Ty->is16bitFPTy()) |
310 | 0 | return ElementCount::getScalable(8); |
311 | 0 | if (Ty->isIntegerTy(8)) |
312 | 0 | return ElementCount::getScalable(16); |
313 | | |
314 | 0 | return std::nullopt; |
315 | 0 | } |
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 | 0 | const SmallVectorImpl<VFParameter> &Params) { |
322 | | // Start with a very wide EC and drop when we find smaller ECs based on type. |
323 | 0 | ElementCount MinEC = |
324 | 0 | ElementCount::getScalable(std::numeric_limits<unsigned int>::max()); |
325 | 0 | 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 | 0 | if (Param.ParamKind == VFParamKind::Vector) { |
329 | 0 | Type *PTy = Signature->getParamType(Param.ParamPos); |
330 | |
|
331 | 0 | std::optional<ElementCount> EC = getElementCountForTy(ISA, PTy); |
332 | | // If we have an unknown scalar element type we can't find a reasonable |
333 | | // VF. |
334 | 0 | if (!EC) |
335 | 0 | return std::nullopt; |
336 | | |
337 | | // Find the smallest VF, based on the widest scalar type. |
338 | 0 | if (ElementCount::isKnownLT(*EC, MinEC)) |
339 | 0 | MinEC = *EC; |
340 | 0 | } |
341 | 0 | } |
342 | | |
343 | | // Also check the return type if not void. |
344 | 0 | Type *RetTy = Signature->getReturnType(); |
345 | 0 | if (!RetTy->isVoidTy()) { |
346 | 0 | std::optional<ElementCount> ReturnEC = getElementCountForTy(ISA, RetTy); |
347 | | // If we have an unknown scalar element type we can't find a reasonable VF. |
348 | 0 | if (!ReturnEC) |
349 | 0 | return std::nullopt; |
350 | 0 | if (ElementCount::isKnownLT(*ReturnEC, MinEC)) |
351 | 0 | MinEC = *ReturnEC; |
352 | 0 | } |
353 | | |
354 | | // The SVE Vector function call ABI bases the VF on the widest element types |
355 | | // present, and vector arguments containing types of that width are always |
356 | | // considered to be packed. Arguments with narrower elements are considered |
357 | | // to be unpacked. |
358 | 0 | if (MinEC.getKnownMinValue() < std::numeric_limits<unsigned int>::max()) |
359 | 0 | return MinEC; |
360 | | |
361 | 0 | return std::nullopt; |
362 | 0 | } |
363 | | } // namespace |
364 | | |
365 | | // Format of the ABI name: |
366 | | // _ZGV<isa><mask><vlen><parameters>_<scalarname>[(<redirection>)] |
367 | | std::optional<VFInfo> VFABI::tryDemangleForVFABI(StringRef MangledName, |
368 | 2.27k | const FunctionType *FTy) { |
369 | 2.27k | const StringRef OriginalName = MangledName; |
370 | | // Assume there is no custom name <redirection>, and therefore the |
371 | | // vector name consists of |
372 | | // _ZGV<isa><mask><vlen><parameters>_<scalarname>. |
373 | 2.27k | StringRef VectorName = MangledName; |
374 | | |
375 | | // Parse the fixed size part of the mangled name |
376 | 2.27k | if (!MangledName.consume_front("_ZGV")) |
377 | 38 | return std::nullopt; |
378 | | |
379 | | // Extract ISA. An unknow ISA is also supported, so we accept all |
380 | | // values. |
381 | 2.23k | VFISAKind ISA; |
382 | 2.23k | if (tryParseISA(MangledName, ISA) != ParseRet::OK) |
383 | 1 | return std::nullopt; |
384 | | |
385 | | // Extract <mask>. |
386 | 2.23k | bool IsMasked; |
387 | 2.23k | if (tryParseMask(MangledName, IsMasked) != ParseRet::OK) |
388 | 66 | return std::nullopt; |
389 | | |
390 | | // Parse the variable size, starting from <vlen>. |
391 | 2.16k | std::pair<unsigned, bool> ParsedVF; |
392 | 2.16k | if (tryParseVLEN(MangledName, ISA, ParsedVF) != ParseRet::OK) |
393 | 152 | return std::nullopt; |
394 | | |
395 | | // Parse the <parameters>. |
396 | 2.01k | ParseRet ParamFound; |
397 | 2.01k | SmallVector<VFParameter, 8> Parameters; |
398 | 7.45M | do { |
399 | 7.45M | const unsigned ParameterPos = Parameters.size(); |
400 | 7.45M | VFParamKind PKind; |
401 | 7.45M | int StepOrPos; |
402 | 7.45M | ParamFound = tryParseParameter(MangledName, PKind, StepOrPos); |
403 | | |
404 | | // Bail off if there is a parsing error in the parsing of the parameter. |
405 | 7.45M | if (ParamFound == ParseRet::Error) |
406 | 277 | return std::nullopt; |
407 | | |
408 | 7.45M | if (ParamFound == ParseRet::OK) { |
409 | 7.45M | Align Alignment; |
410 | | // Look for the alignment token "a <number>". |
411 | 7.45M | const ParseRet AlignFound = tryParseAlign(MangledName, Alignment); |
412 | | // Bail off if there is a syntax error in the align token. |
413 | 7.45M | if (AlignFound == ParseRet::Error) |
414 | 151 | return std::nullopt; |
415 | | |
416 | | // Add the parameter. |
417 | 7.44M | Parameters.push_back({ParameterPos, PKind, StepOrPos, Alignment}); |
418 | 7.44M | } |
419 | 7.45M | } while (ParamFound == ParseRet::OK); |
420 | | |
421 | | // A valid MangledName must have at least one valid entry in the |
422 | | // <parameters>. |
423 | 1.58k | if (Parameters.empty()) |
424 | 114 | return std::nullopt; |
425 | | |
426 | | // If the number of arguments of the scalar function does not match the |
427 | | // vector variant we have just demangled then reject the mapping. |
428 | 1.47k | if (Parameters.size() != FTy->getNumParams()) |
429 | 1.05k | return std::nullopt; |
430 | | |
431 | | // Figure out the number of lanes in vectors for this function variant. This |
432 | | // is easy for fixed length, as the vlen encoding just gives us the value |
433 | | // directly. However, if the vlen mangling indicated that this function |
434 | | // variant expects scalable vectors we need to work it out based on the |
435 | | // demangled parameter types and the scalar function signature. |
436 | 421 | std::optional<ElementCount> EC; |
437 | 421 | if (ParsedVF.second) { |
438 | 0 | EC = getScalableECFromSignature(FTy, ISA, Parameters); |
439 | 0 | if (!EC) |
440 | 0 | return std::nullopt; |
441 | 0 | } else |
442 | 421 | EC = ElementCount::getFixed(ParsedVF.first); |
443 | | |
444 | | // Check for the <scalarname> and the optional <redirection>, which |
445 | | // are separated from the prefix with "_" |
446 | 421 | if (!MangledName.consume_front("_")) |
447 | 0 | return std::nullopt; |
448 | | |
449 | | // The rest of the string must be in the format: |
450 | | // <scalarname>[(<redirection>)] |
451 | 421 | const StringRef ScalarName = |
452 | 2.10k | MangledName.take_while([](char In) { return In != '('; }); |
453 | | |
454 | 421 | if (ScalarName.empty()) |
455 | 0 | return std::nullopt; |
456 | | |
457 | | // Reduce MangledName to [(<redirection>)]. |
458 | 421 | MangledName = MangledName.ltrim(ScalarName); |
459 | | // Find the optional custom name redirection. |
460 | 421 | if (MangledName.consume_front("(")) { |
461 | 421 | if (!MangledName.consume_back(")")) |
462 | 0 | return std::nullopt; |
463 | | // Update the vector variant with the one specified by the user. |
464 | 421 | VectorName = MangledName; |
465 | | // If the vector name is missing, bail out. |
466 | 421 | if (VectorName.empty()) |
467 | 0 | return std::nullopt; |
468 | 421 | } |
469 | | |
470 | | // LLVM internal mapping via the TargetLibraryInfo (TLI) must be |
471 | | // redirected to an existing name. |
472 | 421 | if (ISA == VFISAKind::LLVM && VectorName == OriginalName) |
473 | 0 | return std::nullopt; |
474 | | |
475 | | // When <mask> is "M", we need to add a parameter that is used as |
476 | | // global predicate for the function. |
477 | 421 | if (IsMasked) { |
478 | 0 | const unsigned Pos = Parameters.size(); |
479 | 0 | Parameters.push_back({Pos, VFParamKind::GlobalPredicate}); |
480 | 0 | } |
481 | | |
482 | | // Asserts for parameters of type `VFParamKind::GlobalPredicate`, as |
483 | | // prescribed by the Vector Function ABI specifications supported by |
484 | | // this parser: |
485 | | // 1. Uniqueness. |
486 | | // 2. Must be the last in the parameter list. |
487 | 421 | const auto NGlobalPreds = |
488 | 421 | llvm::count_if(Parameters, [](const VFParameter &PK) { |
489 | 421 | return PK.ParamKind == VFParamKind::GlobalPredicate; |
490 | 421 | }); |
491 | 421 | assert(NGlobalPreds < 2 && "Cannot have more than one global predicate."); |
492 | 421 | if (NGlobalPreds) |
493 | 0 | assert(Parameters.back().ParamKind == VFParamKind::GlobalPredicate && |
494 | 421 | "The global predicate must be the last parameter"); |
495 | | |
496 | 0 | const VFShape Shape({*EC, Parameters}); |
497 | 421 | return VFInfo({Shape, std::string(ScalarName), std::string(VectorName), ISA}); |
498 | 421 | } |
499 | | |
500 | 5.44M | VFParamKind VFABI::getVFParamKindFromString(const StringRef Token) { |
501 | 5.44M | const VFParamKind ParamKind = StringSwitch<VFParamKind>(Token) |
502 | 5.44M | .Case("v", VFParamKind::Vector) |
503 | 5.44M | .Case("l", VFParamKind::OMP_Linear) |
504 | 5.44M | .Case("R", VFParamKind::OMP_LinearRef) |
505 | 5.44M | .Case("L", VFParamKind::OMP_LinearVal) |
506 | 5.44M | .Case("U", VFParamKind::OMP_LinearUVal) |
507 | 5.44M | .Case("ls", VFParamKind::OMP_LinearPos) |
508 | 5.44M | .Case("Ls", VFParamKind::OMP_LinearValPos) |
509 | 5.44M | .Case("Rs", VFParamKind::OMP_LinearRefPos) |
510 | 5.44M | .Case("Us", VFParamKind::OMP_LinearUValPos) |
511 | 5.44M | .Case("u", VFParamKind::OMP_Uniform) |
512 | 5.44M | .Default(VFParamKind::Unknown); |
513 | | |
514 | 5.44M | if (ParamKind != VFParamKind::Unknown) |
515 | 5.44M | return ParamKind; |
516 | | |
517 | | // This function should never be invoked with an invalid input. |
518 | 0 | llvm_unreachable("This fuction should be invoken only on parameters" |
519 | 0 | " that have a textual representation in the mangled name" |
520 | 0 | " of the Vector Function ABI"); |
521 | 0 | } |