1 //===- VFABIDemangler.cpp - Vector Function ABI demangler -----------------===//
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
7 //===----------------------------------------------------------------------===//
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"
20 #define DEBUG_TYPE "vfabi-demangler"
23 /// Utilities for the Vector Function ABI name parser.
25 /// Return types for the parser functions.
29 Error
// Syntax error.
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`.
35 static ParseRet
tryParseISA(StringRef
&MangledName
, VFISAKind
&ISA
) {
36 if (MangledName
.empty())
37 return ParseRet::Error
;
39 if (MangledName
.consume_front(VFABI::_LLVM_
)) {
40 ISA
= VFISAKind::LLVM
;
42 ISA
= StringSwitch
<VFISAKind
>(MangledName
.take_front(1))
43 .Case("n", VFISAKind::AdvancedSIMD
)
44 .Case("s", VFISAKind::SVE
)
45 .Case("b", VFISAKind::SSE
)
46 .Case("c", VFISAKind::AVX
)
47 .Case("d", VFISAKind::AVX2
)
48 .Case("e", VFISAKind::AVX512
)
49 .Default(VFISAKind::Unknown
);
50 MangledName
= MangledName
.drop_front(1);
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`.
59 static ParseRet
tryParseMask(StringRef
&MangledName
, bool &IsMasked
) {
60 if (MangledName
.consume_front("M")) {
65 if (MangledName
.consume_front("N")) {
70 return ParseRet::Error
;
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`.
78 static ParseRet
tryParseVLEN(StringRef
&ParseString
, VFISAKind ISA
,
79 std::pair
<unsigned, bool> &ParsedVF
) {
80 if (ParseString
.consume_front("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
;
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.
96 if (ParseString
.consumeInteger(10, VF
))
97 return ParseRet::Error
;
99 // The token `0` is invalid for VLEN.
101 return ParseRet::Error
;
103 ParsedVF
= {VF
, false};
107 /// The function looks for the following strings at the beginning of
108 /// the input string `ParseString`:
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.
117 /// The function expects <token> to be one of "ls", "Rs", "Us" or
119 static ParseRet
tryParseLinearTokenWithRuntimeStep(StringRef
&ParseString
,
120 VFParamKind
&PKind
, int &Pos
,
121 const StringRef Token
) {
122 if (ParseString
.consume_front(Token
)) {
123 PKind
= VFABI::getVFParamKindFromString(Token
);
124 if (ParseString
.consumeInteger(10, Pos
))
125 return ParseRet::Error
;
129 return ParseRet::None
;
132 /// The function looks for the following string at the beginning of
133 /// the input string `ParseString`:
137 /// <token> is one of "ls", "Rs", "Us" or "Ls".
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.
143 static ParseRet
tryParseLinearWithRuntimeStep(StringRef
&ParseString
,
148 // "ls" <RuntimeStepPos>
149 Ret
= tryParseLinearTokenWithRuntimeStep(ParseString
, PKind
, StepOrPos
, "ls");
150 if (Ret
!= ParseRet::None
)
153 // "Rs" <RuntimeStepPos>
154 Ret
= tryParseLinearTokenWithRuntimeStep(ParseString
, PKind
, StepOrPos
, "Rs");
155 if (Ret
!= ParseRet::None
)
158 // "Ls" <RuntimeStepPos>
159 Ret
= tryParseLinearTokenWithRuntimeStep(ParseString
, PKind
, StepOrPos
, "Ls");
160 if (Ret
!= ParseRet::None
)
163 // "Us" <RuntimeStepPos>
164 Ret
= tryParseLinearTokenWithRuntimeStep(ParseString
, PKind
, StepOrPos
, "Us");
165 if (Ret
!= ParseRet::None
)
168 return ParseRet::None
;
171 /// The function looks for the following strings at the beginning of
172 /// the input string `ParseString`:
174 /// <token> {"n"} <number>
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.
181 /// The function expects <token> to be one of "l", "R", "U" or
183 static ParseRet
tryParseCompileTimeLinearToken(StringRef
&ParseString
,
186 const StringRef Token
) {
187 if (ParseString
.consume_front(Token
)) {
188 PKind
= VFABI::getVFParamKindFromString(Token
);
189 const bool Negate
= ParseString
.consume_front("n");
190 if (ParseString
.consumeInteger(10, LinearStep
))
197 return ParseRet::None
;
200 /// The function looks for the following strings at the beginning of
201 /// the input string `ParseString`:
203 /// ["l" | "R" | "U" | "L"] {"n"} <number>
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.
209 static ParseRet
tryParseLinearWithCompileTimeStep(StringRef
&ParseString
,
212 // "l" {"n"} <CompileTimeStep>
213 if (tryParseCompileTimeLinearToken(ParseString
, PKind
, StepOrPos
, "l") ==
217 // "R" {"n"} <CompileTimeStep>
218 if (tryParseCompileTimeLinearToken(ParseString
, PKind
, StepOrPos
, "R") ==
222 // "L" {"n"} <CompileTimeStep>
223 if (tryParseCompileTimeLinearToken(ParseString
, PKind
, StepOrPos
, "L") ==
227 // "U" {"n"} <CompileTimeStep>
228 if (tryParseCompileTimeLinearToken(ParseString
, PKind
, StepOrPos
, "U") ==
232 return ParseRet::None
;
235 /// Looks into the <parameters> part of the mangled name in search
236 /// for valid paramaters at the beginning of the string
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.
243 static ParseRet
tryParseParameter(StringRef
&ParseString
, VFParamKind
&PKind
,
245 if (ParseString
.consume_front("v")) {
246 PKind
= VFParamKind::Vector
;
251 if (ParseString
.consume_front("u")) {
252 PKind
= VFParamKind::OMP_Uniform
;
257 const ParseRet HasLinearRuntime
=
258 tryParseLinearWithRuntimeStep(ParseString
, PKind
, StepOrPos
);
259 if (HasLinearRuntime
!= ParseRet::None
)
260 return HasLinearRuntime
;
262 const ParseRet HasLinearCompileTime
=
263 tryParseLinearWithCompileTimeStep(ParseString
, PKind
, StepOrPos
);
264 if (HasLinearCompileTime
!= ParseRet::None
)
265 return HasLinearCompileTime
;
267 return ParseRet::None
;
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`.
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.
278 static ParseRet
tryParseAlign(StringRef
&ParseString
, Align
&Alignment
) {
281 if (ParseString
.consume_front("a")) {
282 if (ParseString
.consumeInteger(10, Val
))
283 return ParseRet::Error
;
285 if (!isPowerOf2_64(Val
))
286 return ParseRet::Error
;
288 Alignment
= Align(Val
);
293 return ParseRet::None
;
296 // Returns the 'natural' VF for a given scalar element type, based on the
297 // current architecture.
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.
302 static std::optional
<ElementCount
> getElementCountForTy(const VFISAKind ISA
,
304 // Only AArch64 SVE is supported at present.
305 assert(ISA
== VFISAKind::SVE
&&
306 "Scalable VF decoding only implemented for SVE\n");
308 if (Ty
->isIntegerTy(64) || Ty
->isDoubleTy() || Ty
->isPointerTy())
309 return ElementCount::getScalable(2);
310 if (Ty
->isIntegerTy(32) || Ty
->isFloatTy())
311 return ElementCount::getScalable(4);
312 if (Ty
->isIntegerTy(16) || Ty
->is16bitFPTy())
313 return ElementCount::getScalable(8);
314 if (Ty
->isIntegerTy(8))
315 return ElementCount::getScalable(16);
320 // Extract the VectorizationFactor from a given function signature, based
321 // on the widest scalar element types that will become vector parameters.
322 static std::optional
<ElementCount
>
323 getScalableECFromSignature(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.
327 ElementCount::getScalable(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(Param
.ParamPos
);
334 std::optional
<ElementCount
> EC
= getElementCountForTy(ISA
, PTy
);
335 // If we have an unknown scalar element type we can't find a reasonable
340 // Find the smallest VF, based on the widest scalar type.
341 if (ElementCount::isKnownLT(*EC
, MinEC
))
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
, RetTy
);
350 // If we have an unknown scalar element type we can't find a reasonable VF.
353 if (ElementCount::isKnownLT(*ReturnEC
, MinEC
))
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
361 if (MinEC
.getKnownMinValue() < std::numeric_limits
<unsigned int>::max())
368 // Format of the ABI name:
369 // _ZGV<isa><mask><vlen><parameters>_<scalarname>[(<redirection>)]
370 std::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
;
378 // Parse the fixed size part of the mangled name
379 if (!MangledName
.consume_front("_ZGV"))
382 // Extract ISA. An unknow ISA is also supported, so we accept all
385 if (tryParseISA(MangledName
, ISA
) != ParseRet::OK
)
390 if (tryParseMask(MangledName
, IsMasked
) != ParseRet::OK
)
393 // Parse the variable size, starting from <vlen>.
394 std::pair
<unsigned, bool> ParsedVF
;
395 if (tryParseVLEN(MangledName
, ISA
, ParsedVF
) != ParseRet::OK
)
398 // Parse the <parameters>.
400 SmallVector
<VFParameter
, 8> Parameters
;
402 const unsigned ParameterPos
= Parameters
.size();
405 ParamFound
= tryParseParameter(MangledName
, PKind
, StepOrPos
);
407 // Bail off if there is a parsing error in the parsing of the parameter.
408 if (ParamFound
== ParseRet::Error
)
411 if (ParamFound
== ParseRet::OK
) {
413 // Look for the alignment token "a <number>".
414 const ParseRet AlignFound
= tryParseAlign(MangledName
, Alignment
);
415 // Bail off if there is a syntax error in the align token.
416 if (AlignFound
== ParseRet::Error
)
419 // Add the parameter.
420 Parameters
.push_back({ParameterPos
, PKind
, StepOrPos
, Alignment
});
422 } while (ParamFound
== ParseRet::OK
);
424 // A valid MangledName must have at least one valid entry in the
426 if (Parameters
.empty())
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())
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(FTy
, ISA
, Parameters
);
445 EC
= ElementCount::getFixed(ParsedVF
.first
);
447 // Check for the <scalarname> and the optional <redirection>, which
448 // are separated from the prefix with "_"
449 if (!MangledName
.consume_front("_"))
452 // The rest of the string must be in the format:
453 // <scalarname>[(<redirection>)]
454 const StringRef ScalarName
=
455 MangledName
.take_while([](char In
) { return In
!= '('; });
457 if (ScalarName
.empty())
460 // Reduce MangledName to [(<redirection>)].
461 MangledName
= MangledName
.ltrim(ScalarName
);
462 // Find the optional custom name redirection.
463 if (MangledName
.consume_front("(")) {
464 if (!MangledName
.consume_back(")"))
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())
473 // LLVM internal mapping via the TargetLibraryInfo (TLI) must be
474 // redirected to an existing name.
475 if (ISA
== VFISAKind::LLVM
&& VectorName
== OriginalName
)
478 // When <mask> is "M", we need to add a parameter that is used as
479 // global predicate for the function.
481 const unsigned Pos
= Parameters
.size();
482 Parameters
.push_back({Pos
, VFParamKind::GlobalPredicate
});
485 // Asserts for parameters of type `VFParamKind::GlobalPredicate`, as
486 // prescribed by the Vector Function ABI specifications supported by
489 // 2. Must be the last in the parameter list.
490 const auto NGlobalPreds
=
491 llvm::count_if(Parameters
, [](const VFParameter
&PK
) {
492 return PK
.ParamKind
== VFParamKind::GlobalPredicate
;
494 assert(NGlobalPreds
< 2 && "Cannot have more than one global predicate.");
496 assert(Parameters
.back().ParamKind
== VFParamKind::GlobalPredicate
&&
497 "The global predicate must be the last parameter");
499 const VFShape
Shape({*EC
, Parameters
});
500 return VFInfo({Shape
, std::string(ScalarName
), std::string(VectorName
), ISA
});
503 VFParamKind
VFABI::getVFParamKindFromString(const StringRef Token
) {
504 const VFParamKind ParamKind
= StringSwitch
<VFParamKind
>(Token
)
505 .Case("v", VFParamKind::Vector
)
506 .Case("l", VFParamKind::OMP_Linear
)
507 .Case("R", VFParamKind::OMP_LinearRef
)
508 .Case("L", VFParamKind::OMP_LinearVal
)
509 .Case("U", VFParamKind::OMP_LinearUVal
)
510 .Case("ls", VFParamKind::OMP_LinearPos
)
511 .Case("Ls", VFParamKind::OMP_LinearValPos
)
512 .Case("Rs", VFParamKind::OMP_LinearRefPos
)
513 .Case("Us", VFParamKind::OMP_LinearUValPos
)
514 .Case("u", VFParamKind::OMP_Uniform
)
515 .Default(VFParamKind::Unknown
);
517 if (ParamKind
!= VFParamKind::Unknown
)
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");
526 void VFABI::getVectorVariantNames(
527 const CallInst
&CI
, SmallVectorImpl
<std::string
> &VariantMappings
) {
528 const StringRef S
= CI
.getFnAttr(VFABI::MappingsAttrName
).getValueAsString();
532 SmallVector
<StringRef
, 8> ListAttr
;
533 S
.split(ListAttr
, ",");
535 for (const auto &S
: SetVector
<StringRef
>(ListAttr
.begin(), ListAttr
.end())) {
536 std::optional
<VFInfo
> Info
=
537 VFABI::tryDemangleForVFABI(S
, CI
.getFunctionType());
538 if (Info
&& CI
.getModule()->getFunction(Info
->VectorName
)) {
539 LLVM_DEBUG(dbgs() << "VFABI: Adding mapping '" << S
<< "' for " << CI
541 VariantMappings
.push_back(std::string(S
));
543 LLVM_DEBUG(dbgs() << "VFABI: Invalid mapping '" << S
<< "'\n");
547 FunctionType
*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
) {
556 VectorType::get(Type::getInt1Ty(ScalarFTy
->getContext()), VF
);
557 VecTypes
.push_back(MaskTy
);
561 Type
*OperandTy
= ScalarFTy
->getParamType(ScalarParamIndex
++);
562 if (VFParam
.ParamKind
== VFParamKind::Vector
)
563 OperandTy
= VectorType::get(OperandTy
, VF
);
564 VecTypes
.push_back(OperandTy
);
567 auto *RetTy
= ScalarFTy
->getReturnType();
568 if (!RetTy
->isVoidTy())
569 RetTy
= VectorType::get(RetTy
, VF
);
570 return FunctionType::get(RetTy
, VecTypes
, false);
573 void VFABI::setVectorVariantNames(CallInst
*CI
,
574 ArrayRef
<std::string
> VariantMappings
) {
575 if (VariantMappings
.empty())
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.");
586 Module
*M
= CI
->getModule();
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.");
599 Attribute::get(M
->getContext(), MappingsAttrName
, Buffer
.str()));
602 bool VFShape::hasValidParameterList() const {
603 for (unsigned Pos
= 0, NumParams
= Parameters
.size(); Pos
< NumParams
;
605 assert(Parameters
[Pos
].ParamPos
== Pos
&& "Broken parameter list.");
607 switch (Parameters
[Pos
].ParamKind
) {
608 default: // Nothing to check.
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)
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
))
626 // The linear step parameter must be marked as uniform.
627 if (Parameters
[Parameters
[Pos
].LinearStepOrPos
].ParamKind
!=
628 VFParamKind::OMP_Uniform
)
630 // The linear step parameter can't point at itself.
631 if (Parameters
[Pos
].LinearStepOrPos
== int(Pos
))
634 case VFParamKind::GlobalPredicate
:
635 // The global predicate must be the unique. Can be placed anywhere in the
637 for (unsigned NextPos
= Pos
+ 1; NextPos
< NumParams
; ++NextPos
)
638 if (Parameters
[NextPos
].ParamKind
== VFParamKind::GlobalPredicate
)