1//===- VFABIDemangler.cpp - Vector Function ABI demangler -----------------===//
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/IR/VFABIDemangler.h"
10#include "llvm/ADT/SetVector.h"
11#include "llvm/ADT/SmallString.h"
12#include "llvm/ADT/StringSwitch.h"
13#include "llvm/IR/Module.h"
14#include "llvm/Support/Debug.h"
15#include "llvm/Support/raw_ostream.h"
16#include <limits>
17
18using namespace llvm;
19
20#define DEBUG_TYPE "vfabi-demangler"
21
22namespace {
23/// Utilities for the Vector Function ABI name parser.
24
25/// Return types for the parser functions.
26enum class ParseRet {
27 OK, // Found.
28 None, // Not found.
29 Error // Syntax error.
30};
31
32/// Extracts the `<isa>` information from the mangled string, and
33/// sets the `ISA` accordingly. If successful, the <isa> token is removed
34/// from the input string `MangledName`.
35static ParseRet tryParseISA(StringRef &MangledName, VFISAKind &ISA) {
36 if (MangledName.empty())
37 return ParseRet::Error;
38
39 if (MangledName.consume_front(Prefix: VFABI::_LLVM_)) {
40 ISA = VFISAKind::LLVM;
41 } else {
42 ISA = StringSwitch<VFISAKind>(MangledName.take_front(N: 1))
43 .Case(S: "n", Value: VFISAKind::AdvancedSIMD)
44 .Case(S: "s", Value: VFISAKind::SVE)
45 .Case(S: "b", Value: VFISAKind::SSE)
46 .Case(S: "c", Value: VFISAKind::AVX)
47 .Case(S: "d", Value: VFISAKind::AVX2)
48 .Case(S: "e", Value: VFISAKind::AVX512)
49 .Default(Value: VFISAKind::Unknown);
50 MangledName = MangledName.drop_front(N: 1);
51 }
52
53 return ParseRet::OK;
54}
55
56/// Extracts the `<mask>` information from the mangled string, and
57/// sets `IsMasked` accordingly. If successful, the <mask> token is removed
58/// from the input string `MangledName`.
59static ParseRet tryParseMask(StringRef &MangledName, bool &IsMasked) {
60 if (MangledName.consume_front(Prefix: "M")) {
61 IsMasked = true;
62 return ParseRet::OK;
63 }
64
65 if (MangledName.consume_front(Prefix: "N")) {
66 IsMasked = false;
67 return ParseRet::OK;
68 }
69
70 return ParseRet::Error;
71}
72
73/// Extract the `<vlen>` information from the mangled string, and
74/// sets `ParsedVF` accordingly. A `<vlen> == "x"` token is interpreted as a
75/// scalable vector length and the boolean is set to true, otherwise a nonzero
76/// unsigned integer will be directly used as a VF. On success, the `<vlen>`
77/// token is removed from the input string `ParseString`.
78static ParseRet tryParseVLEN(StringRef &ParseString, VFISAKind ISA,
79 std::pair<unsigned, bool> &ParsedVF) {
80 if (ParseString.consume_front(Prefix: "x")) {
81 // SVE is the only scalable ISA currently supported.
82 if (ISA != VFISAKind::SVE) {
83 LLVM_DEBUG(dbgs() << "Vector function variant declared with scalable VF "
84 << "but ISA is not SVE\n");
85 return ParseRet::Error;
86 }
87 // We can't determine the VF of a scalable vector by looking at the vlen
88 // string (just 'x'), so say we successfully parsed it but return a 'true'
89 // for the scalable field with an invalid VF field so that we know to look
90 // up the actual VF based on element types from the parameters or return.
91 ParsedVF = {0, true};
92 return ParseRet::OK;
93 }
94
95 unsigned VF = 0;
96 if (ParseString.consumeInteger(Radix: 10, Result&: VF))
97 return ParseRet::Error;
98
99 // The token `0` is invalid for VLEN.
100 if (VF == 0)
101 return ParseRet::Error;
102
103 ParsedVF = {VF, false};
104 return ParseRet::OK;
105}
106
107/// The function looks for the following strings at the beginning of
108/// the input string `ParseString`:
109///
110/// <token> <number>
111///
112/// On success, it removes the parsed parameter from `ParseString`,
113/// sets `PKind` to the correspondent enum value, sets `Pos` to
114/// <number>, and return success. On a syntax error, it return a
115/// parsing error. If nothing is parsed, it returns std::nullopt.
116///
117/// The function expects <token> to be one of "ls", "Rs", "Us" or
118/// "Ls".
119static ParseRet tryParseLinearTokenWithRuntimeStep(StringRef &ParseString,
120 VFParamKind &PKind, int &Pos,
121 const StringRef Token) {
122 if (ParseString.consume_front(Prefix: Token)) {
123 PKind = VFABI::getVFParamKindFromString(Token);
124 if (ParseString.consumeInteger(Radix: 10, Result&: Pos))
125 return ParseRet::Error;
126 return ParseRet::OK;
127 }
128
129 return ParseRet::None;
130}
131
132/// The function looks for the following string at the beginning of
133/// the input string `ParseString`:
134///
135/// <token> <number>
136///
137/// <token> is one of "ls", "Rs", "Us" or "Ls".
138///
139/// On success, it removes the parsed parameter from `ParseString`,
140/// sets `PKind` to the correspondent enum value, sets `StepOrPos` to
141/// <number>, and return success. On a syntax error, it return a
142/// parsing error. If nothing is parsed, it returns std::nullopt.
143static ParseRet tryParseLinearWithRuntimeStep(StringRef &ParseString,
144 VFParamKind &PKind,
145 int &StepOrPos) {
146 ParseRet Ret;
147
148 // "ls" <RuntimeStepPos>
149 Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, Pos&: StepOrPos, Token: "ls");
150 if (Ret != ParseRet::None)
151 return Ret;
152
153 // "Rs" <RuntimeStepPos>
154 Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, Pos&: StepOrPos, Token: "Rs");
155 if (Ret != ParseRet::None)
156 return Ret;
157
158 // "Ls" <RuntimeStepPos>
159 Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, Pos&: StepOrPos, Token: "Ls");
160 if (Ret != ParseRet::None)
161 return Ret;
162
163 // "Us" <RuntimeStepPos>
164 Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, Pos&: StepOrPos, Token: "Us");
165 if (Ret != ParseRet::None)
166 return Ret;
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/// <token> {"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 std::nullopt.
180///
181/// The function expects <token> to be one of "l", "R", "U" or
182/// "L".
183static ParseRet tryParseCompileTimeLinearToken(StringRef &ParseString,
184 VFParamKind &PKind,
185 int &LinearStep,
186 const StringRef Token) {
187 if (ParseString.consume_front(Prefix: Token)) {
188 PKind = VFABI::getVFParamKindFromString(Token);
189 const bool Negate = ParseString.consume_front(Prefix: "n");
190 if (ParseString.consumeInteger(Radix: 10, Result&: LinearStep))
191 LinearStep = 1;
192 if (Negate)
193 LinearStep *= -1;
194 return ParseRet::OK;
195 }
196
197 return ParseRet::None;
198}
199
200/// The function looks for the following strings at the beginning of
201/// the input string `ParseString`:
202///
203/// ["l" | "R" | "U" | "L"] {"n"} <number>
204///
205/// On success, it removes the parsed parameter from `ParseString`,
206/// sets `PKind` to the correspondent enum value, sets `LinearStep` to
207/// <number>, and return success. On a syntax error, it return a
208/// parsing error. If nothing is parsed, it returns std::nullopt.
209static ParseRet tryParseLinearWithCompileTimeStep(StringRef &ParseString,
210 VFParamKind &PKind,
211 int &StepOrPos) {
212 // "l" {"n"} <CompileTimeStep>
213 if (tryParseCompileTimeLinearToken(ParseString, PKind, LinearStep&: StepOrPos, Token: "l") ==
214 ParseRet::OK)
215 return ParseRet::OK;
216
217 // "R" {"n"} <CompileTimeStep>
218 if (tryParseCompileTimeLinearToken(ParseString, PKind, LinearStep&: StepOrPos, Token: "R") ==
219 ParseRet::OK)
220 return ParseRet::OK;
221
222 // "L" {"n"} <CompileTimeStep>
223 if (tryParseCompileTimeLinearToken(ParseString, PKind, LinearStep&: StepOrPos, Token: "L") ==
224 ParseRet::OK)
225 return ParseRet::OK;
226
227 // "U" {"n"} <CompileTimeStep>
228 if (tryParseCompileTimeLinearToken(ParseString, PKind, LinearStep&: StepOrPos, Token: "U") ==
229 ParseRet::OK)
230 return ParseRet::OK;
231
232 return ParseRet::None;
233}
234
235/// Looks into the <parameters> part of the mangled name in search
236/// for valid paramaters at the beginning of the string
237/// `ParseString`.
238///
239/// On success, it removes the parsed parameter from `ParseString`,
240/// sets `PKind` to the correspondent enum value, sets `StepOrPos`
241/// accordingly, and return success. On a syntax error, it return a
242/// parsing error. If nothing is parsed, it returns std::nullopt.
243static ParseRet tryParseParameter(StringRef &ParseString, VFParamKind &PKind,
244 int &StepOrPos) {
245 if (ParseString.consume_front(Prefix: "v")) {
246 PKind = VFParamKind::Vector;
247 StepOrPos = 0;
248 return ParseRet::OK;
249 }
250
251 if (ParseString.consume_front(Prefix: "u")) {
252 PKind = VFParamKind::OMP_Uniform;
253 StepOrPos = 0;
254 return ParseRet::OK;
255 }
256
257 const ParseRet HasLinearRuntime =
258 tryParseLinearWithRuntimeStep(ParseString, PKind, StepOrPos);
259 if (HasLinearRuntime != ParseRet::None)
260 return HasLinearRuntime;
261
262 const ParseRet HasLinearCompileTime =
263 tryParseLinearWithCompileTimeStep(ParseString, PKind, StepOrPos);
264 if (HasLinearCompileTime != ParseRet::None)
265 return HasLinearCompileTime;
266
267 return ParseRet::None;
268}
269
270/// Looks into the <parameters> part of the mangled name in search
271/// of a valid 'aligned' clause. The function should be invoked
272/// after parsing a parameter via `tryParseParameter`.
273///
274/// On success, it removes the parsed parameter from `ParseString`,
275/// sets `PKind` to the correspondent enum value, sets `StepOrPos`
276/// accordingly, and return success. On a syntax error, it return a
277/// parsing error. If nothing is parsed, it returns std::nullopt.
278static ParseRet tryParseAlign(StringRef &ParseString, Align &Alignment) {
279 uint64_t Val;
280 // "a" <number>
281 if (ParseString.consume_front(Prefix: "a")) {
282 if (ParseString.consumeInteger(Radix: 10, Result&: Val))
283 return ParseRet::Error;
284
285 if (!isPowerOf2_64(Value: Val))
286 return ParseRet::Error;
287
288 Alignment = Align(Val);
289
290 return ParseRet::OK;
291 }
292
293 return ParseRet::None;
294}
295
296// Returns the 'natural' VF for a given scalar element type, based on the
297// current architecture.
298//
299// For SVE (currently the only scalable architecture with a defined name
300// mangling), we assume a minimum vector size of 128b and return a VF based on
301// the number of elements of the given type which would fit in such a vector.
302static std::optional<ElementCount> getElementCountForTy(const VFISAKind ISA,
303 const Type *Ty) {
304 // Only AArch64 SVE is supported at present.
305 assert(ISA == VFISAKind::SVE &&
306 "Scalable VF decoding only implemented for SVE\n");
307
308 if (Ty->isIntegerTy(Bitwidth: 64) || Ty->isDoubleTy() || Ty->isPointerTy())
309 return ElementCount::getScalable(MinVal: 2);
310 if (Ty->isIntegerTy(Bitwidth: 32) || Ty->isFloatTy())
311 return ElementCount::getScalable(MinVal: 4);
312 if (Ty->isIntegerTy(Bitwidth: 16) || Ty->is16bitFPTy())
313 return ElementCount::getScalable(MinVal: 8);
314 if (Ty->isIntegerTy(Bitwidth: 8))
315 return ElementCount::getScalable(MinVal: 16);
316
317 return std::nullopt;
318}
319
320// Extract the VectorizationFactor from a given function signature, based
321// on the widest scalar element types that will become vector parameters.
322static std::optional<ElementCount>
323getScalableECFromSignature(const FunctionType *Signature, const VFISAKind ISA,
324 const SmallVectorImpl<VFParameter> &Params) {
325 // Start with a very wide EC and drop when we find smaller ECs based on type.
326 ElementCount MinEC =
327 ElementCount::getScalable(MinVal: std::numeric_limits<unsigned int>::max());
328 for (auto &Param : Params) {
329 // Only vector parameters are used when determining the VF; uniform or
330 // linear are left as scalars, so do not affect VF.
331 if (Param.ParamKind == VFParamKind::Vector) {
332 Type *PTy = Signature->getParamType(i: Param.ParamPos);
333
334 std::optional<ElementCount> EC = getElementCountForTy(ISA, Ty: PTy);
335 // If we have an unknown scalar element type we can't find a reasonable
336 // VF.
337 if (!EC)
338 return std::nullopt;
339
340 // Find the smallest VF, based on the widest scalar type.
341 if (ElementCount::isKnownLT(LHS: *EC, RHS: MinEC))
342 MinEC = *EC;
343 }
344 }
345
346 // Also check the return type if not void.
347 Type *RetTy = Signature->getReturnType();
348 if (!RetTy->isVoidTy()) {
349 std::optional<ElementCount> ReturnEC = getElementCountForTy(ISA, Ty: RetTy);
350 // If we have an unknown scalar element type we can't find a reasonable VF.
351 if (!ReturnEC)
352 return std::nullopt;
353 if (ElementCount::isKnownLT(LHS: *ReturnEC, RHS: MinEC))
354 MinEC = *ReturnEC;
355 }
356
357 // The SVE Vector function call ABI bases the VF on the widest element types
358 // present, and vector arguments containing types of that width are always
359 // considered to be packed. Arguments with narrower elements are considered
360 // to be unpacked.
361 if (MinEC.getKnownMinValue() < std::numeric_limits<unsigned int>::max())
362 return MinEC;
363
364 return std::nullopt;
365}
366} // namespace
367
368// Format of the ABI name:
369// _ZGV<isa><mask><vlen><parameters>_<scalarname>[(<redirection>)]
370std::optional<VFInfo> VFABI::tryDemangleForVFABI(StringRef MangledName,
371 const FunctionType *FTy) {
372 const StringRef OriginalName = MangledName;
373 // Assume there is no custom name <redirection>, and therefore the
374 // vector name consists of
375 // _ZGV<isa><mask><vlen><parameters>_<scalarname>.
376 StringRef VectorName = MangledName;
377
378 // Parse the fixed size part of the mangled name
379 if (!MangledName.consume_front(Prefix: "_ZGV"))
380 return std::nullopt;
381
382 // Extract ISA. An unknow ISA is also supported, so we accept all
383 // values.
384 VFISAKind ISA;
385 if (tryParseISA(MangledName, ISA) != ParseRet::OK)
386 return std::nullopt;
387
388 // Extract <mask>.
389 bool IsMasked;
390 if (tryParseMask(MangledName, IsMasked) != ParseRet::OK)
391 return std::nullopt;
392
393 // Parse the variable size, starting from <vlen>.
394 std::pair<unsigned, bool> ParsedVF;
395 if (tryParseVLEN(ParseString&: MangledName, ISA, ParsedVF) != ParseRet::OK)
396 return std::nullopt;
397
398 // Parse the <parameters>.
399 ParseRet ParamFound;
400 SmallVector<VFParameter, 8> Parameters;
401 do {
402 const unsigned ParameterPos = Parameters.size();
403 VFParamKind PKind;
404 int StepOrPos;
405 ParamFound = tryParseParameter(ParseString&: MangledName, PKind, StepOrPos);
406
407 // Bail off if there is a parsing error in the parsing of the parameter.
408 if (ParamFound == ParseRet::Error)
409 return std::nullopt;
410
411 if (ParamFound == ParseRet::OK) {
412 Align Alignment;
413 // Look for the alignment token "a <number>".
414 const ParseRet AlignFound = tryParseAlign(ParseString&: MangledName, Alignment);
415 // Bail off if there is a syntax error in the align token.
416 if (AlignFound == ParseRet::Error)
417 return std::nullopt;
418
419 // Add the parameter.
420 Parameters.push_back(Elt: {.ParamPos: ParameterPos, .ParamKind: PKind, .LinearStepOrPos: StepOrPos, .Alignment: Alignment});
421 }
422 } while (ParamFound == ParseRet::OK);
423
424 // A valid MangledName must have at least one valid entry in the
425 // <parameters>.
426 if (Parameters.empty())
427 return std::nullopt;
428
429 // If the number of arguments of the scalar function does not match the
430 // vector variant we have just demangled then reject the mapping.
431 if (Parameters.size() != FTy->getNumParams())
432 return std::nullopt;
433
434 // Figure out the number of lanes in vectors for this function variant. This
435 // is easy for fixed length, as the vlen encoding just gives us the value
436 // directly. However, if the vlen mangling indicated that this function
437 // variant expects scalable vectors we need to work it out based on the
438 // demangled parameter types and the scalar function signature.
439 std::optional<ElementCount> EC;
440 if (ParsedVF.second) {
441 EC = getScalableECFromSignature(Signature: FTy, ISA, Params: Parameters);
442 if (!EC)
443 return std::nullopt;
444 } else
445 EC = ElementCount::getFixed(MinVal: ParsedVF.first);
446
447 // Check for the <scalarname> and the optional <redirection>, which
448 // are separated from the prefix with "_"
449 if (!MangledName.consume_front(Prefix: "_"))
450 return std::nullopt;
451
452 // The rest of the string must be in the format:
453 // <scalarname>[(<redirection>)]
454 const StringRef ScalarName =
455 MangledName.take_while(F: [](char In) { return In != '('; });
456
457 if (ScalarName.empty())
458 return std::nullopt;
459
460 // Reduce MangledName to [(<redirection>)].
461 MangledName = MangledName.ltrim(Chars: ScalarName);
462 // Find the optional custom name redirection.
463 if (MangledName.consume_front(Prefix: "(")) {
464 if (!MangledName.consume_back(Suffix: ")"))
465 return std::nullopt;
466 // Update the vector variant with the one specified by the user.
467 VectorName = MangledName;
468 // If the vector name is missing, bail out.
469 if (VectorName.empty())
470 return std::nullopt;
471 }
472
473 // LLVM internal mapping via the TargetLibraryInfo (TLI) must be
474 // redirected to an existing name.
475 if (ISA == VFISAKind::LLVM && VectorName == OriginalName)
476 return std::nullopt;
477
478 // When <mask> is "M", we need to add a parameter that is used as
479 // global predicate for the function.
480 if (IsMasked) {
481 const unsigned Pos = Parameters.size();
482 Parameters.push_back(Elt: {.ParamPos: Pos, .ParamKind: VFParamKind::GlobalPredicate});
483 }
484
485 // Asserts for parameters of type `VFParamKind::GlobalPredicate`, as
486 // prescribed by the Vector Function ABI specifications supported by
487 // this parser:
488 // 1. Uniqueness.
489 // 2. Must be the last in the parameter list.
490 const auto NGlobalPreds =
491 llvm::count_if(Range&: Parameters, P: [](const VFParameter &PK) {
492 return PK.ParamKind == VFParamKind::GlobalPredicate;
493 });
494 assert(NGlobalPreds < 2 && "Cannot have more than one global predicate.");
495 if (NGlobalPreds)
496 assert(Parameters.back().ParamKind == VFParamKind::GlobalPredicate &&
497 "The global predicate must be the last parameter");
498
499 const VFShape Shape({.VF: *EC, .Parameters: Parameters});
500 return VFInfo({.Shape: Shape, .ScalarName: std::string(ScalarName), .VectorName: std::string(VectorName), .ISA: ISA});
501}
502
503VFParamKind VFABI::getVFParamKindFromString(const StringRef Token) {
504 const VFParamKind ParamKind = StringSwitch<VFParamKind>(Token)
505 .Case(S: "v", Value: VFParamKind::Vector)
506 .Case(S: "l", Value: VFParamKind::OMP_Linear)
507 .Case(S: "R", Value: VFParamKind::OMP_LinearRef)
508 .Case(S: "L", Value: VFParamKind::OMP_LinearVal)
509 .Case(S: "U", Value: VFParamKind::OMP_LinearUVal)
510 .Case(S: "ls", Value: VFParamKind::OMP_LinearPos)
511 .Case(S: "Ls", Value: VFParamKind::OMP_LinearValPos)
512 .Case(S: "Rs", Value: VFParamKind::OMP_LinearRefPos)
513 .Case(S: "Us", Value: VFParamKind::OMP_LinearUValPos)
514 .Case(S: "u", Value: VFParamKind::OMP_Uniform)
515 .Default(Value: VFParamKind::Unknown);
516
517 if (ParamKind != VFParamKind::Unknown)
518 return ParamKind;
519
520 // This function should never be invoked with an invalid input.
521 llvm_unreachable("This fuction should be invoken only on parameters"
522 " that have a textual representation in the mangled name"
523 " of the Vector Function ABI");
524}
525
526void VFABI::getVectorVariantNames(
527 const CallInst &CI, SmallVectorImpl<std::string> &VariantMappings) {
528 const StringRef S = CI.getFnAttr(Kind: VFABI::MappingsAttrName).getValueAsString();
529 if (S.empty())
530 return;
531
532 SmallVector<StringRef, 8> ListAttr;
533 S.split(A&: ListAttr, Separator: ",");
534
535 for (const auto &S : SetVector<StringRef>(ListAttr.begin(), ListAttr.end())) {
536 std::optional<VFInfo> Info =
537 VFABI::tryDemangleForVFABI(MangledName: S, FTy: CI.getFunctionType());
538 if (Info && CI.getModule()->getFunction(Name: Info->VectorName)) {
539 LLVM_DEBUG(dbgs() << "VFABI: Adding mapping '" << S << "' for " << CI
540 << "\n");
541 VariantMappings.push_back(Elt: std::string(S));
542 } else
543 LLVM_DEBUG(dbgs() << "VFABI: Invalid mapping '" << S << "'\n");
544 }
545}
546
547FunctionType *VFABI::createFunctionType(const VFInfo &Info,
548 const FunctionType *ScalarFTy) {
549 // Create vector parameter types
550 SmallVector<Type *, 8> VecTypes;
551 ElementCount VF = Info.Shape.VF;
552 int ScalarParamIndex = 0;
553 for (auto VFParam : Info.Shape.Parameters) {
554 if (VFParam.ParamKind == VFParamKind::GlobalPredicate) {
555 VectorType *MaskTy =
556 VectorType::get(ElementType: Type::getInt1Ty(C&: ScalarFTy->getContext()), EC: VF);
557 VecTypes.push_back(Elt: MaskTy);
558 continue;
559 }
560
561 Type *OperandTy = ScalarFTy->getParamType(i: ScalarParamIndex++);
562 if (VFParam.ParamKind == VFParamKind::Vector)
563 OperandTy = VectorType::get(ElementType: OperandTy, EC: VF);
564 VecTypes.push_back(Elt: OperandTy);
565 }
566
567 auto *RetTy = ScalarFTy->getReturnType();
568 if (!RetTy->isVoidTy())
569 RetTy = VectorType::get(ElementType: RetTy, EC: VF);
570 return FunctionType::get(Result: RetTy, Params: VecTypes, isVarArg: false);
571}
572
573void VFABI::setVectorVariantNames(CallInst *CI,
574 ArrayRef<std::string> VariantMappings) {
575 if (VariantMappings.empty())
576 return;
577
578 SmallString<256> Buffer;
579 llvm::raw_svector_ostream Out(Buffer);
580 for (const std::string &VariantMapping : VariantMappings)
581 Out << VariantMapping << ",";
582 // Get rid of the trailing ','.
583 assert(!Buffer.str().empty() && "Must have at least one char.");
584 Buffer.pop_back();
585
586 Module *M = CI->getModule();
587#ifndef NDEBUG
588 for (const std::string &VariantMapping : VariantMappings) {
589 LLVM_DEBUG(dbgs() << "VFABI: adding mapping '" << VariantMapping << "'\n");
590 std::optional<VFInfo> VI =
591 VFABI::tryDemangleForVFABI(VariantMapping, CI->getFunctionType());
592 assert(VI && "Cannot add an invalid VFABI name.");
593 assert(M->getNamedValue(VI->VectorName) &&
594 "Cannot add variant to attribute: "
595 "vector function declaration is missing.");
596 }
597#endif
598 CI->addFnAttr(
599 Attr: Attribute::get(Context&: M->getContext(), Kind: MappingsAttrName, Val: Buffer.str()));
600}
601
602bool VFShape::hasValidParameterList() const {
603 for (unsigned Pos = 0, NumParams = Parameters.size(); Pos < NumParams;
604 ++Pos) {
605 assert(Parameters[Pos].ParamPos == Pos && "Broken parameter list.");
606
607 switch (Parameters[Pos].ParamKind) {
608 default: // Nothing to check.
609 break;
610 case VFParamKind::OMP_Linear:
611 case VFParamKind::OMP_LinearRef:
612 case VFParamKind::OMP_LinearVal:
613 case VFParamKind::OMP_LinearUVal:
614 // Compile time linear steps must be non-zero.
615 if (Parameters[Pos].LinearStepOrPos == 0)
616 return false;
617 break;
618 case VFParamKind::OMP_LinearPos:
619 case VFParamKind::OMP_LinearRefPos:
620 case VFParamKind::OMP_LinearValPos:
621 case VFParamKind::OMP_LinearUValPos:
622 // The runtime linear step must be referring to some other
623 // parameters in the signature.
624 if (Parameters[Pos].LinearStepOrPos >= int(NumParams))
625 return false;
626 // The linear step parameter must be marked as uniform.
627 if (Parameters[Parameters[Pos].LinearStepOrPos].ParamKind !=
628 VFParamKind::OMP_Uniform)
629 return false;
630 // The linear step parameter can't point at itself.
631 if (Parameters[Pos].LinearStepOrPos == int(Pos))
632 return false;
633 break;
634 case VFParamKind::GlobalPredicate:
635 // The global predicate must be the unique. Can be placed anywhere in the
636 // signature.
637 for (unsigned NextPos = Pos + 1; NextPos < NumParams; ++NextPos)
638 if (Parameters[NextPos].ParamKind == VFParamKind::GlobalPredicate)
639 return false;
640 break;
641 }
642 }
643 return true;
644}
645