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