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