blob: 6fd8ae63f5f07b80920ba50da56fa6ec899b5ad8 [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
9#include "llvm/Analysis/VectorUtils.h"
10
11using namespace llvm;
12
13namespace {
14/// Utilities for the Vector Function ABI name parser.
15
16/// Return types for the parser functions.
17enum 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.
25ParseRet 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.
46ParseRet 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///
65ParseRet 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".
91ParseRet 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.
115ParseRet 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".
154ParseRet 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.
179ParseRet 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.
213ParseRet 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.
234ParseRet 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.
267ParseRet 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>)]
288Optional<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
397VFParamKind 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}