123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481 |
- //===- VFABIDemangling.cpp - Vector Function ABI demangling utilities. ---===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/ADT/SmallSet.h"
- #include "llvm/ADT/SmallString.h"
- #include "llvm/Analysis/VectorUtils.h"
- using namespace llvm;
- namespace {
- /// Utilities for the Vector Function ABI name parser.
- /// Return types for the parser functions.
- enum class ParseRet {
- OK, // Found.
- None, // Not found.
- Error // Syntax error.
- };
- /// Extracts the `<isa>` information from the mangled string, and
- /// sets the `ISA` accordingly.
- ParseRet tryParseISA(StringRef &MangledName, VFISAKind &ISA) {
- if (MangledName.empty())
- return ParseRet::Error;
- if (MangledName.startswith(VFABI::_LLVM_)) {
- MangledName = MangledName.drop_front(strlen(VFABI::_LLVM_));
- ISA = VFISAKind::LLVM;
- } else {
- ISA = StringSwitch<VFISAKind>(MangledName.take_front(1))
- .Case("n", VFISAKind::AdvancedSIMD)
- .Case("s", VFISAKind::SVE)
- .Case("b", VFISAKind::SSE)
- .Case("c", VFISAKind::AVX)
- .Case("d", VFISAKind::AVX2)
- .Case("e", VFISAKind::AVX512)
- .Default(VFISAKind::Unknown);
- MangledName = MangledName.drop_front(1);
- }
- return ParseRet::OK;
- }
- /// Extracts the `<mask>` information from the mangled string, and
- /// sets `IsMasked` accordingly. The input string `MangledName` is
- /// left unmodified.
- ParseRet tryParseMask(StringRef &MangledName, bool &IsMasked) {
- if (MangledName.consume_front("M")) {
- IsMasked = true;
- return ParseRet::OK;
- }
- if (MangledName.consume_front("N")) {
- IsMasked = false;
- return ParseRet::OK;
- }
- return ParseRet::Error;
- }
- /// Extract the `<vlen>` information from the mangled string, and
- /// sets `VF` accordingly. A `<vlen> == "x"` token is interpreted as a scalable
- /// vector length. On success, the `<vlen>` token is removed from
- /// the input string `ParseString`.
- ///
- ParseRet tryParseVLEN(StringRef &ParseString, unsigned &VF, bool &IsScalable) {
- if (ParseString.consume_front("x")) {
- // Set VF to 0, to be later adjusted to a value grater than zero
- // by looking at the signature of the vector function with
- // `getECFromSignature`.
- VF = 0;
- IsScalable = true;
- return ParseRet::OK;
- }
- if (ParseString.consumeInteger(10, VF))
- return ParseRet::Error;
- // The token `0` is invalid for VLEN.
- if (VF == 0)
- return ParseRet::Error;
- IsScalable = false;
- return ParseRet::OK;
- }
- /// The function looks for the following strings at the beginning of
- /// the input string `ParseString`:
- ///
- /// <token> <number>
- ///
- /// On success, it removes the parsed parameter from `ParseString`,
- /// sets `PKind` to the correspondent enum value, sets `Pos` to
- /// <number>, and return success. On a syntax error, it return a
- /// parsing error. If nothing is parsed, it returns None.
- ///
- /// The function expects <token> to be one of "ls", "Rs", "Us" or
- /// "Ls".
- ParseRet tryParseLinearTokenWithRuntimeStep(StringRef &ParseString,
- VFParamKind &PKind, int &Pos,
- const StringRef Token) {
- if (ParseString.consume_front(Token)) {
- PKind = VFABI::getVFParamKindFromString(Token);
- if (ParseString.consumeInteger(10, Pos))
- return ParseRet::Error;
- return ParseRet::OK;
- }
- return ParseRet::None;
- }
- /// The function looks for the following stringt at the beginning of
- /// the input string `ParseString`:
- ///
- /// <token> <number>
- ///
- /// <token> is one of "ls", "Rs", "Us" or "Ls".
- ///
- /// On success, it removes the parsed parameter from `ParseString`,
- /// sets `PKind` to the correspondent enum value, sets `StepOrPos` to
- /// <number>, and return success. On a syntax error, it return a
- /// parsing error. If nothing is parsed, it returns None.
- ParseRet tryParseLinearWithRuntimeStep(StringRef &ParseString,
- VFParamKind &PKind, int &StepOrPos) {
- ParseRet Ret;
- // "ls" <RuntimeStepPos>
- Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "ls");
- if (Ret != ParseRet::None)
- return Ret;
- // "Rs" <RuntimeStepPos>
- Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Rs");
- if (Ret != ParseRet::None)
- return Ret;
- // "Ls" <RuntimeStepPos>
- Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Ls");
- if (Ret != ParseRet::None)
- return Ret;
- // "Us" <RuntimeStepPos>
- Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Us");
- if (Ret != ParseRet::None)
- return Ret;
- return ParseRet::None;
- }
- /// The function looks for the following strings at the beginning of
- /// the input string `ParseString`:
- ///
- /// <token> {"n"} <number>
- ///
- /// On success, it removes the parsed parameter from `ParseString`,
- /// sets `PKind` to the correspondent enum value, sets `LinearStep` to
- /// <number>, and return success. On a syntax error, it return a
- /// parsing error. If nothing is parsed, it returns None.
- ///
- /// The function expects <token> to be one of "l", "R", "U" or
- /// "L".
- ParseRet tryParseCompileTimeLinearToken(StringRef &ParseString,
- VFParamKind &PKind, int &LinearStep,
- const StringRef Token) {
- if (ParseString.consume_front(Token)) {
- PKind = VFABI::getVFParamKindFromString(Token);
- const bool Negate = ParseString.consume_front("n");
- if (ParseString.consumeInteger(10, LinearStep))
- LinearStep = 1;
- if (Negate)
- LinearStep *= -1;
- return ParseRet::OK;
- }
- return ParseRet::None;
- }
- /// The function looks for the following strings at the beginning of
- /// the input string `ParseString`:
- ///
- /// ["l" | "R" | "U" | "L"] {"n"} <number>
- ///
- /// On success, it removes the parsed parameter from `ParseString`,
- /// sets `PKind` to the correspondent enum value, sets `LinearStep` to
- /// <number>, and return success. On a syntax error, it return a
- /// parsing error. If nothing is parsed, it returns None.
- ParseRet tryParseLinearWithCompileTimeStep(StringRef &ParseString,
- VFParamKind &PKind, int &StepOrPos) {
- // "l" {"n"} <CompileTimeStep>
- if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "l") ==
- ParseRet::OK)
- return ParseRet::OK;
- // "R" {"n"} <CompileTimeStep>
- if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "R") ==
- ParseRet::OK)
- return ParseRet::OK;
- // "L" {"n"} <CompileTimeStep>
- if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "L") ==
- ParseRet::OK)
- return ParseRet::OK;
- // "U" {"n"} <CompileTimeStep>
- if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "U") ==
- ParseRet::OK)
- return ParseRet::OK;
- return ParseRet::None;
- }
- /// Looks into the <parameters> part of the mangled name in search
- /// for valid paramaters at the beginning of the string
- /// `ParseString`.
- ///
- /// On success, it removes the parsed parameter from `ParseString`,
- /// sets `PKind` to the correspondent enum value, sets `StepOrPos`
- /// accordingly, and return success. On a syntax error, it return a
- /// parsing error. If nothing is parsed, it returns None.
- ParseRet tryParseParameter(StringRef &ParseString, VFParamKind &PKind,
- int &StepOrPos) {
- if (ParseString.consume_front("v")) {
- PKind = VFParamKind::Vector;
- StepOrPos = 0;
- return ParseRet::OK;
- }
- if (ParseString.consume_front("u")) {
- PKind = VFParamKind::OMP_Uniform;
- StepOrPos = 0;
- return ParseRet::OK;
- }
- const ParseRet HasLinearRuntime =
- tryParseLinearWithRuntimeStep(ParseString, PKind, StepOrPos);
- if (HasLinearRuntime != ParseRet::None)
- return HasLinearRuntime;
- const ParseRet HasLinearCompileTime =
- tryParseLinearWithCompileTimeStep(ParseString, PKind, StepOrPos);
- if (HasLinearCompileTime != ParseRet::None)
- return HasLinearCompileTime;
- return ParseRet::None;
- }
- /// Looks into the <parameters> part of the mangled name in search
- /// of a valid 'aligned' clause. The function should be invoked
- /// after parsing a parameter via `tryParseParameter`.
- ///
- /// On success, it removes the parsed parameter from `ParseString`,
- /// sets `PKind` to the correspondent enum value, sets `StepOrPos`
- /// accordingly, and return success. On a syntax error, it return a
- /// parsing error. If nothing is parsed, it returns None.
- ParseRet tryParseAlign(StringRef &ParseString, Align &Alignment) {
- uint64_t Val;
- // "a" <number>
- if (ParseString.consume_front("a")) {
- if (ParseString.consumeInteger(10, Val))
- return ParseRet::Error;
- if (!isPowerOf2_64(Val))
- return ParseRet::Error;
- Alignment = Align(Val);
- return ParseRet::OK;
- }
- return ParseRet::None;
- }
- #ifndef NDEBUG
- // Verify the assumtion that all vectors in the signature of a vector
- // function have the same number of elements.
- bool verifyAllVectorsHaveSameWidth(FunctionType *Signature) {
- SmallVector<VectorType *, 2> VecTys;
- if (auto *RetTy = dyn_cast<VectorType>(Signature->getReturnType()))
- VecTys.push_back(RetTy);
- for (auto *Ty : Signature->params())
- if (auto *VTy = dyn_cast<VectorType>(Ty))
- VecTys.push_back(VTy);
- if (VecTys.size() <= 1)
- return true;
- assert(VecTys.size() > 1 && "Invalid number of elements.");
- const ElementCount EC = VecTys[0]->getElementCount();
- return llvm::all_of(llvm::drop_begin(VecTys), [&EC](VectorType *VTy) {
- return (EC == VTy->getElementCount());
- });
- }
- #endif // NDEBUG
- // Extract the VectorizationFactor from a given function signature,
- // under the assumtion that all vectors have the same number of
- // elements, i.e. same ElementCount.Min.
- ElementCount getECFromSignature(FunctionType *Signature) {
- assert(verifyAllVectorsHaveSameWidth(Signature) &&
- "Invalid vector signature.");
- if (auto *RetTy = dyn_cast<VectorType>(Signature->getReturnType()))
- return RetTy->getElementCount();
- for (auto *Ty : Signature->params())
- if (auto *VTy = dyn_cast<VectorType>(Ty))
- return VTy->getElementCount();
- return ElementCount::getFixed(/*Min=*/1);
- }
- } // namespace
- // Format of the ABI name:
- // _ZGV<isa><mask><vlen><parameters>_<scalarname>[(<redirection>)]
- Optional<VFInfo> VFABI::tryDemangleForVFABI(StringRef MangledName,
- const Module &M) {
- const StringRef OriginalName = MangledName;
- // Assume there is no custom name <redirection>, and therefore the
- // vector name consists of
- // _ZGV<isa><mask><vlen><parameters>_<scalarname>.
- StringRef VectorName = MangledName;
- // Parse the fixed size part of the manled name
- if (!MangledName.consume_front("_ZGV"))
- return None;
- // Extract ISA. An unknow ISA is also supported, so we accept all
- // values.
- VFISAKind ISA;
- if (tryParseISA(MangledName, ISA) != ParseRet::OK)
- return None;
- // Extract <mask>.
- bool IsMasked;
- if (tryParseMask(MangledName, IsMasked) != ParseRet::OK)
- return None;
- // Parse the variable size, starting from <vlen>.
- unsigned VF;
- bool IsScalable;
- if (tryParseVLEN(MangledName, VF, IsScalable) != ParseRet::OK)
- return None;
- // Parse the <parameters>.
- ParseRet ParamFound;
- SmallVector<VFParameter, 8> Parameters;
- do {
- const unsigned ParameterPos = Parameters.size();
- VFParamKind PKind;
- int StepOrPos;
- ParamFound = tryParseParameter(MangledName, PKind, StepOrPos);
- // Bail off if there is a parsing error in the parsing of the parameter.
- if (ParamFound == ParseRet::Error)
- return None;
- if (ParamFound == ParseRet::OK) {
- Align Alignment;
- // Look for the alignment token "a <number>".
- const ParseRet AlignFound = tryParseAlign(MangledName, Alignment);
- // Bail off if there is a syntax error in the align token.
- if (AlignFound == ParseRet::Error)
- return None;
- // Add the parameter.
- Parameters.push_back({ParameterPos, PKind, StepOrPos, Alignment});
- }
- } while (ParamFound == ParseRet::OK);
- // A valid MangledName must have at least one valid entry in the
- // <parameters>.
- if (Parameters.empty())
- return None;
- // Check for the <scalarname> and the optional <redirection>, which
- // are separated from the prefix with "_"
- if (!MangledName.consume_front("_"))
- return None;
- // The rest of the string must be in the format:
- // <scalarname>[(<redirection>)]
- const StringRef ScalarName =
- MangledName.take_while([](char In) { return In != '('; });
- if (ScalarName.empty())
- return None;
- // Reduce MangledName to [(<redirection>)].
- MangledName = MangledName.ltrim(ScalarName);
- // Find the optional custom name redirection.
- if (MangledName.consume_front("(")) {
- if (!MangledName.consume_back(")"))
- return None;
- // Update the vector variant with the one specified by the user.
- VectorName = MangledName;
- // If the vector name is missing, bail out.
- if (VectorName.empty())
- return None;
- }
- // LLVM internal mapping via the TargetLibraryInfo (TLI) must be
- // redirected to an existing name.
- if (ISA == VFISAKind::LLVM && VectorName == OriginalName)
- return None;
- // When <mask> is "M", we need to add a parameter that is used as
- // global predicate for the function.
- if (IsMasked) {
- const unsigned Pos = Parameters.size();
- Parameters.push_back({Pos, VFParamKind::GlobalPredicate});
- }
- // Asserts for parameters of type `VFParamKind::GlobalPredicate`, as
- // prescribed by the Vector Function ABI specifications supported by
- // this parser:
- // 1. Uniqueness.
- // 2. Must be the last in the parameter list.
- const auto NGlobalPreds = std::count_if(
- Parameters.begin(), Parameters.end(), [](const VFParameter PK) {
- return PK.ParamKind == VFParamKind::GlobalPredicate;
- });
- assert(NGlobalPreds < 2 && "Cannot have more than one global predicate.");
- if (NGlobalPreds)
- assert(Parameters.back().ParamKind == VFParamKind::GlobalPredicate &&
- "The global predicate must be the last parameter");
- // Adjust the VF for scalable signatures. The EC.Min is not encoded
- // in the name of the function, but it is encoded in the IR
- // signature of the function. We need to extract this information
- // because it is needed by the loop vectorizer, which reasons in
- // terms of VectorizationFactor or ElementCount. In particular, we
- // need to make sure that the VF field of the VFShape class is never
- // set to 0.
- if (IsScalable) {
- const Function *F = M.getFunction(VectorName);
- // The declaration of the function must be present in the module
- // to be able to retrieve its signature.
- if (!F)
- return None;
- const ElementCount EC = getECFromSignature(F->getFunctionType());
- VF = EC.getKnownMinValue();
- }
- // 1. We don't accept a zero lanes vectorization factor.
- // 2. We don't accept the demangling if the vector function is not
- // present in the module.
- if (VF == 0)
- return None;
- if (!M.getFunction(VectorName))
- return None;
- const VFShape Shape({ElementCount::get(VF, IsScalable), Parameters});
- return VFInfo({Shape, std::string(ScalarName), std::string(VectorName), ISA});
- }
- VFParamKind VFABI::getVFParamKindFromString(const StringRef Token) {
- const VFParamKind ParamKind = StringSwitch<VFParamKind>(Token)
- .Case("v", VFParamKind::Vector)
- .Case("l", VFParamKind::OMP_Linear)
- .Case("R", VFParamKind::OMP_LinearRef)
- .Case("L", VFParamKind::OMP_LinearVal)
- .Case("U", VFParamKind::OMP_LinearUVal)
- .Case("ls", VFParamKind::OMP_LinearPos)
- .Case("Ls", VFParamKind::OMP_LinearValPos)
- .Case("Rs", VFParamKind::OMP_LinearRefPos)
- .Case("Us", VFParamKind::OMP_LinearUValPos)
- .Case("u", VFParamKind::OMP_Uniform)
- .Default(VFParamKind::Unknown);
- if (ParamKind != VFParamKind::Unknown)
- return ParamKind;
- // This function should never be invoked with an invalid input.
- llvm_unreachable("This fuction should be invoken only on parameters"
- " that have a textual representation in the mangled name"
- " of the Vector Function ABI");
- }
|