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