1353940Sdim//===- VFABIDemangling.cpp - Vector Function ABI demangling utilities. ---===// 2353940Sdim// 3353940Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353940Sdim// See https://llvm.org/LICENSE.txt for license information. 5353940Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6353940Sdim// 7353940Sdim//===----------------------------------------------------------------------===// 8353940Sdim 9357095Sdim#include "llvm/ADT/SmallSet.h" 10357095Sdim#include "llvm/ADT/SmallString.h" 11353940Sdim#include "llvm/Analysis/VectorUtils.h" 12353940Sdim 13353940Sdimusing namespace llvm; 14353940Sdim 15353940Sdimnamespace { 16353940Sdim/// Utilities for the Vector Function ABI name parser. 17353940Sdim 18353940Sdim/// Return types for the parser functions. 19353940Sdimenum class ParseRet { 20353940Sdim OK, // Found. 21353940Sdim None, // Not found. 22353940Sdim Error // Syntax error. 23353940Sdim}; 24353940Sdim 25353940Sdim/// Extracts the `<isa>` information from the mangled string, and 26353940Sdim/// sets the `ISA` accordingly. 27353940SdimParseRet tryParseISA(StringRef &MangledName, VFISAKind &ISA) { 28353940Sdim if (MangledName.empty()) 29353940Sdim return ParseRet::Error; 30353940Sdim 31357095Sdim if (MangledName.startswith(VFABI::_LLVM_)) { 32357095Sdim MangledName = MangledName.drop_front(strlen(VFABI::_LLVM_)); 33357095Sdim ISA = VFISAKind::LLVM; 34357095Sdim } else { 35357095Sdim ISA = StringSwitch<VFISAKind>(MangledName.take_front(1)) 36357095Sdim .Case("n", VFISAKind::AdvancedSIMD) 37357095Sdim .Case("s", VFISAKind::SVE) 38357095Sdim .Case("b", VFISAKind::SSE) 39357095Sdim .Case("c", VFISAKind::AVX) 40357095Sdim .Case("d", VFISAKind::AVX2) 41357095Sdim .Case("e", VFISAKind::AVX512) 42357095Sdim .Default(VFISAKind::Unknown); 43357095Sdim MangledName = MangledName.drop_front(1); 44357095Sdim } 45353940Sdim 46353940Sdim return ParseRet::OK; 47353940Sdim} 48353940Sdim 49353940Sdim/// Extracts the `<mask>` information from the mangled string, and 50353940Sdim/// sets `IsMasked` accordingly. The input string `MangledName` is 51353940Sdim/// left unmodified. 52353940SdimParseRet tryParseMask(StringRef &MangledName, bool &IsMasked) { 53353940Sdim if (MangledName.consume_front("M")) { 54353940Sdim IsMasked = true; 55353940Sdim return ParseRet::OK; 56353940Sdim } 57353940Sdim 58353940Sdim if (MangledName.consume_front("N")) { 59353940Sdim IsMasked = false; 60353940Sdim return ParseRet::OK; 61353940Sdim } 62353940Sdim 63353940Sdim return ParseRet::Error; 64353940Sdim} 65353940Sdim 66353940Sdim/// Extract the `<vlen>` information from the mangled string, and 67353940Sdim/// sets `VF` accordingly. A `<vlen> == "x"` token is interpreted as a scalable 68353940Sdim/// vector length. On success, the `<vlen>` token is removed from 69353940Sdim/// the input string `ParseString`. 70353940Sdim/// 71353940SdimParseRet tryParseVLEN(StringRef &ParseString, unsigned &VF, bool &IsScalable) { 72353940Sdim if (ParseString.consume_front("x")) { 73353940Sdim VF = 0; 74353940Sdim IsScalable = true; 75353940Sdim return ParseRet::OK; 76353940Sdim } 77353940Sdim 78353940Sdim if (ParseString.consumeInteger(10, VF)) 79353940Sdim return ParseRet::Error; 80353940Sdim 81353940Sdim IsScalable = false; 82353940Sdim return ParseRet::OK; 83353940Sdim} 84353940Sdim 85353940Sdim/// The function looks for the following strings at the beginning of 86353940Sdim/// the input string `ParseString`: 87353940Sdim/// 88353940Sdim/// <token> <number> 89353940Sdim/// 90353940Sdim/// On success, it removes the parsed parameter from `ParseString`, 91353940Sdim/// sets `PKind` to the correspondent enum value, sets `Pos` to 92353940Sdim/// <number>, and return success. On a syntax error, it return a 93353940Sdim/// parsing error. If nothing is parsed, it returns None. 94353940Sdim/// 95353940Sdim/// The function expects <token> to be one of "ls", "Rs", "Us" or 96353940Sdim/// "Ls". 97353940SdimParseRet tryParseLinearTokenWithRuntimeStep(StringRef &ParseString, 98353940Sdim VFParamKind &PKind, int &Pos, 99353940Sdim const StringRef Token) { 100353940Sdim if (ParseString.consume_front(Token)) { 101353940Sdim PKind = VFABI::getVFParamKindFromString(Token); 102353940Sdim if (ParseString.consumeInteger(10, Pos)) 103353940Sdim return ParseRet::Error; 104353940Sdim return ParseRet::OK; 105353940Sdim } 106353940Sdim 107353940Sdim return ParseRet::None; 108353940Sdim} 109353940Sdim 110353940Sdim/// The function looks for the following stringt at the beginning of 111353940Sdim/// the input string `ParseString`: 112353940Sdim/// 113353940Sdim/// <token> <number> 114353940Sdim/// 115353940Sdim/// <token> is one of "ls", "Rs", "Us" or "Ls". 116353940Sdim/// 117353940Sdim/// On success, it removes the parsed parameter from `ParseString`, 118353940Sdim/// sets `PKind` to the correspondent enum value, sets `StepOrPos` to 119353940Sdim/// <number>, and return success. On a syntax error, it return a 120353940Sdim/// parsing error. If nothing is parsed, it returns None. 121353940SdimParseRet tryParseLinearWithRuntimeStep(StringRef &ParseString, 122353940Sdim VFParamKind &PKind, int &StepOrPos) { 123353940Sdim ParseRet Ret; 124353940Sdim 125353940Sdim // "ls" <RuntimeStepPos> 126353940Sdim Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "ls"); 127353940Sdim if (Ret != ParseRet::None) 128353940Sdim return Ret; 129353940Sdim 130353940Sdim // "Rs" <RuntimeStepPos> 131353940Sdim Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Rs"); 132353940Sdim if (Ret != ParseRet::None) 133353940Sdim return Ret; 134353940Sdim 135353940Sdim // "Ls" <RuntimeStepPos> 136353940Sdim Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Ls"); 137353940Sdim if (Ret != ParseRet::None) 138353940Sdim return Ret; 139353940Sdim 140353940Sdim // "Us" <RuntimeStepPos> 141353940Sdim Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Us"); 142353940Sdim if (Ret != ParseRet::None) 143353940Sdim return Ret; 144353940Sdim 145353940Sdim return ParseRet::None; 146353940Sdim} 147353940Sdim 148353940Sdim/// The function looks for the following strings at the beginning of 149353940Sdim/// the input string `ParseString`: 150353940Sdim/// 151353940Sdim/// <token> {"n"} <number> 152353940Sdim/// 153353940Sdim/// On success, it removes the parsed parameter from `ParseString`, 154353940Sdim/// sets `PKind` to the correspondent enum value, sets `LinearStep` to 155353940Sdim/// <number>, and return success. On a syntax error, it return a 156353940Sdim/// parsing error. If nothing is parsed, it returns None. 157353940Sdim/// 158353940Sdim/// The function expects <token> to be one of "l", "R", "U" or 159353940Sdim/// "L". 160353940SdimParseRet tryParseCompileTimeLinearToken(StringRef &ParseString, 161353940Sdim VFParamKind &PKind, int &LinearStep, 162353940Sdim const StringRef Token) { 163353940Sdim if (ParseString.consume_front(Token)) { 164353940Sdim PKind = VFABI::getVFParamKindFromString(Token); 165353940Sdim const bool Negate = ParseString.consume_front("n"); 166353940Sdim if (ParseString.consumeInteger(10, LinearStep)) 167353940Sdim LinearStep = 1; 168353940Sdim if (Negate) 169353940Sdim LinearStep *= -1; 170353940Sdim return ParseRet::OK; 171353940Sdim } 172353940Sdim 173353940Sdim return ParseRet::None; 174353940Sdim} 175353940Sdim 176353940Sdim/// The function looks for the following strings at the beginning of 177353940Sdim/// the input string `ParseString`: 178353940Sdim/// 179353940Sdim/// ["l" | "R" | "U" | "L"] {"n"} <number> 180353940Sdim/// 181353940Sdim/// On success, it removes the parsed parameter from `ParseString`, 182353940Sdim/// sets `PKind` to the correspondent enum value, sets `LinearStep` to 183353940Sdim/// <number>, and return success. On a syntax error, it return a 184353940Sdim/// parsing error. If nothing is parsed, it returns None. 185353940SdimParseRet tryParseLinearWithCompileTimeStep(StringRef &ParseString, 186353940Sdim VFParamKind &PKind, int &StepOrPos) { 187353940Sdim // "l" {"n"} <CompileTimeStep> 188353940Sdim if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "l") == 189353940Sdim ParseRet::OK) 190353940Sdim return ParseRet::OK; 191353940Sdim 192353940Sdim // "R" {"n"} <CompileTimeStep> 193353940Sdim if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "R") == 194353940Sdim ParseRet::OK) 195353940Sdim return ParseRet::OK; 196353940Sdim 197353940Sdim // "L" {"n"} <CompileTimeStep> 198353940Sdim if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "L") == 199353940Sdim ParseRet::OK) 200353940Sdim return ParseRet::OK; 201353940Sdim 202353940Sdim // "U" {"n"} <CompileTimeStep> 203353940Sdim if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "U") == 204353940Sdim ParseRet::OK) 205353940Sdim return ParseRet::OK; 206353940Sdim 207353940Sdim return ParseRet::None; 208353940Sdim} 209353940Sdim 210353940Sdim/// The function looks for the following strings at the beginning of 211353940Sdim/// the input string `ParseString`: 212353940Sdim/// 213353940Sdim/// "u" <number> 214353940Sdim/// 215353940Sdim/// On success, it removes the parsed parameter from `ParseString`, 216353940Sdim/// sets `PKind` to the correspondent enum value, sets `Pos` to 217353940Sdim/// <number>, and return success. On a syntax error, it return a 218353940Sdim/// parsing error. If nothing is parsed, it returns None. 219353940SdimParseRet tryParseUniform(StringRef &ParseString, VFParamKind &PKind, int &Pos) { 220353940Sdim // "u" <Pos> 221353940Sdim const char *UniformToken = "u"; 222353940Sdim if (ParseString.consume_front(UniformToken)) { 223353940Sdim PKind = VFABI::getVFParamKindFromString(UniformToken); 224353940Sdim if (ParseString.consumeInteger(10, Pos)) 225353940Sdim return ParseRet::Error; 226353940Sdim 227353940Sdim return ParseRet::OK; 228353940Sdim } 229353940Sdim return ParseRet::None; 230353940Sdim} 231353940Sdim 232353940Sdim/// Looks into the <parameters> part of the mangled name in search 233353940Sdim/// for valid paramaters at the beginning of the string 234353940Sdim/// `ParseString`. 235353940Sdim/// 236353940Sdim/// On success, it removes the parsed parameter from `ParseString`, 237353940Sdim/// sets `PKind` to the correspondent enum value, sets `StepOrPos` 238353940Sdim/// accordingly, and return success. On a syntax error, it return a 239353940Sdim/// parsing error. If nothing is parsed, it returns None. 240353940SdimParseRet tryParseParameter(StringRef &ParseString, VFParamKind &PKind, 241353940Sdim int &StepOrPos) { 242353940Sdim if (ParseString.consume_front("v")) { 243353940Sdim PKind = VFParamKind::Vector; 244353940Sdim StepOrPos = 0; 245353940Sdim return ParseRet::OK; 246353940Sdim } 247353940Sdim 248353940Sdim const ParseRet HasLinearRuntime = 249353940Sdim tryParseLinearWithRuntimeStep(ParseString, PKind, StepOrPos); 250353940Sdim if (HasLinearRuntime != ParseRet::None) 251353940Sdim return HasLinearRuntime; 252353940Sdim 253353940Sdim const ParseRet HasLinearCompileTime = 254353940Sdim tryParseLinearWithCompileTimeStep(ParseString, PKind, StepOrPos); 255353940Sdim if (HasLinearCompileTime != ParseRet::None) 256353940Sdim return HasLinearCompileTime; 257353940Sdim 258353940Sdim const ParseRet HasUniform = tryParseUniform(ParseString, PKind, StepOrPos); 259353940Sdim if (HasUniform != ParseRet::None) 260353940Sdim return HasUniform; 261353940Sdim 262353940Sdim return ParseRet::None; 263353940Sdim} 264353940Sdim 265353940Sdim/// Looks into the <parameters> part of the mangled name in search 266353940Sdim/// of a valid 'aligned' clause. The function should be invoked 267353940Sdim/// after parsing a parameter via `tryParseParameter`. 268353940Sdim/// 269353940Sdim/// On success, it removes the parsed parameter from `ParseString`, 270353940Sdim/// sets `PKind` to the correspondent enum value, sets `StepOrPos` 271353940Sdim/// accordingly, and return success. On a syntax error, it return a 272353940Sdim/// parsing error. If nothing is parsed, it returns None. 273353940SdimParseRet tryParseAlign(StringRef &ParseString, Align &Alignment) { 274353940Sdim uint64_t Val; 275353940Sdim // "a" <number> 276353940Sdim if (ParseString.consume_front("a")) { 277353940Sdim if (ParseString.consumeInteger(10, Val)) 278353940Sdim return ParseRet::Error; 279353940Sdim 280353940Sdim if (!isPowerOf2_64(Val)) 281353940Sdim return ParseRet::Error; 282353940Sdim 283353940Sdim Alignment = Align(Val); 284353940Sdim 285353940Sdim return ParseRet::OK; 286353940Sdim } 287353940Sdim 288353940Sdim return ParseRet::None; 289353940Sdim} 290353940Sdim} // namespace 291353940Sdim 292353940Sdim// Format of the ABI name: 293353940Sdim// _ZGV<isa><mask><vlen><parameters>_<scalarname>[(<redirection>)] 294353940SdimOptional<VFInfo> VFABI::tryDemangleForVFABI(StringRef MangledName) { 295357095Sdim const StringRef OriginalName = MangledName; 296353940Sdim // Assume there is no custom name <redirection>, and therefore the 297353940Sdim // vector name consists of 298353940Sdim // _ZGV<isa><mask><vlen><parameters>_<scalarname>. 299353940Sdim StringRef VectorName = MangledName; 300353940Sdim 301353940Sdim // Parse the fixed size part of the manled name 302353940Sdim if (!MangledName.consume_front("_ZGV")) 303353940Sdim return None; 304353940Sdim 305353940Sdim // Extract ISA. An unknow ISA is also supported, so we accept all 306353940Sdim // values. 307353940Sdim VFISAKind ISA; 308353940Sdim if (tryParseISA(MangledName, ISA) != ParseRet::OK) 309353940Sdim return None; 310353940Sdim 311353940Sdim // Extract <mask>. 312353940Sdim bool IsMasked; 313353940Sdim if (tryParseMask(MangledName, IsMasked) != ParseRet::OK) 314353940Sdim return None; 315353940Sdim 316353940Sdim // Parse the variable size, starting from <vlen>. 317353940Sdim unsigned VF; 318353940Sdim bool IsScalable; 319353940Sdim if (tryParseVLEN(MangledName, VF, IsScalable) != ParseRet::OK) 320353940Sdim return None; 321353940Sdim 322353940Sdim // Parse the <parameters>. 323353940Sdim ParseRet ParamFound; 324353940Sdim SmallVector<VFParameter, 8> Parameters; 325353940Sdim do { 326353940Sdim const unsigned ParameterPos = Parameters.size(); 327353940Sdim VFParamKind PKind; 328353940Sdim int StepOrPos; 329353940Sdim ParamFound = tryParseParameter(MangledName, PKind, StepOrPos); 330353940Sdim 331353940Sdim // Bail off if there is a parsing error in the parsing of the parameter. 332353940Sdim if (ParamFound == ParseRet::Error) 333353940Sdim return None; 334353940Sdim 335353940Sdim if (ParamFound == ParseRet::OK) { 336353940Sdim Align Alignment; 337353940Sdim // Look for the alignment token "a <number>". 338353940Sdim const ParseRet AlignFound = tryParseAlign(MangledName, Alignment); 339353940Sdim // Bail off if there is a syntax error in the align token. 340353940Sdim if (AlignFound == ParseRet::Error) 341353940Sdim return None; 342353940Sdim 343353940Sdim // Add the parameter. 344353940Sdim Parameters.push_back({ParameterPos, PKind, StepOrPos, Alignment}); 345353940Sdim } 346353940Sdim } while (ParamFound == ParseRet::OK); 347353940Sdim 348357095Sdim // A valid MangledName must have at least one valid entry in the 349353940Sdim // <parameters>. 350353940Sdim if (Parameters.empty()) 351353940Sdim return None; 352353940Sdim 353353940Sdim // Check for the <scalarname> and the optional <redirection>, which 354353940Sdim // are separated from the prefix with "_" 355353940Sdim if (!MangledName.consume_front("_")) 356353940Sdim return None; 357353940Sdim 358353940Sdim // The rest of the string must be in the format: 359353940Sdim // <scalarname>[(<redirection>)] 360353940Sdim const StringRef ScalarName = 361353940Sdim MangledName.take_while([](char In) { return In != '('; }); 362353940Sdim 363353940Sdim if (ScalarName.empty()) 364353940Sdim return None; 365353940Sdim 366353940Sdim // Reduce MangledName to [(<redirection>)]. 367353940Sdim MangledName = MangledName.ltrim(ScalarName); 368353940Sdim // Find the optional custom name redirection. 369353940Sdim if (MangledName.consume_front("(")) { 370353940Sdim if (!MangledName.consume_back(")")) 371353940Sdim return None; 372353940Sdim // Update the vector variant with the one specified by the user. 373353940Sdim VectorName = MangledName; 374353940Sdim // If the vector name is missing, bail out. 375353940Sdim if (VectorName.empty()) 376353940Sdim return None; 377353940Sdim } 378353940Sdim 379357095Sdim // LLVM internal mapping via the TargetLibraryInfo (TLI) must be 380357095Sdim // redirected to an existing name. 381357095Sdim if (ISA == VFISAKind::LLVM && VectorName == OriginalName) 382357095Sdim return None; 383357095Sdim 384353940Sdim // When <mask> is "M", we need to add a parameter that is used as 385353940Sdim // global predicate for the function. 386353940Sdim if (IsMasked) { 387353940Sdim const unsigned Pos = Parameters.size(); 388353940Sdim Parameters.push_back({Pos, VFParamKind::GlobalPredicate}); 389353940Sdim } 390353940Sdim 391353940Sdim // Asserts for parameters of type `VFParamKind::GlobalPredicate`, as 392353940Sdim // prescribed by the Vector Function ABI specifications supported by 393353940Sdim // this parser: 394353940Sdim // 1. Uniqueness. 395353940Sdim // 2. Must be the last in the parameter list. 396353940Sdim const auto NGlobalPreds = std::count_if( 397353940Sdim Parameters.begin(), Parameters.end(), [](const VFParameter PK) { 398353940Sdim return PK.ParamKind == VFParamKind::GlobalPredicate; 399353940Sdim }); 400353940Sdim assert(NGlobalPreds < 2 && "Cannot have more than one global predicate."); 401353940Sdim if (NGlobalPreds) 402353940Sdim assert(Parameters.back().ParamKind == VFParamKind::GlobalPredicate && 403353940Sdim "The global predicate must be the last parameter"); 404353940Sdim 405357095Sdim const VFShape Shape({VF, IsScalable, Parameters}); 406357095Sdim return VFInfo({Shape, ScalarName, VectorName, ISA}); 407353940Sdim} 408353940Sdim 409353940SdimVFParamKind VFABI::getVFParamKindFromString(const StringRef Token) { 410353940Sdim const VFParamKind ParamKind = StringSwitch<VFParamKind>(Token) 411353940Sdim .Case("v", VFParamKind::Vector) 412353940Sdim .Case("l", VFParamKind::OMP_Linear) 413353940Sdim .Case("R", VFParamKind::OMP_LinearRef) 414353940Sdim .Case("L", VFParamKind::OMP_LinearVal) 415353940Sdim .Case("U", VFParamKind::OMP_LinearUVal) 416353940Sdim .Case("ls", VFParamKind::OMP_LinearPos) 417353940Sdim .Case("Ls", VFParamKind::OMP_LinearValPos) 418353940Sdim .Case("Rs", VFParamKind::OMP_LinearRefPos) 419353940Sdim .Case("Us", VFParamKind::OMP_LinearUValPos) 420353940Sdim .Case("u", VFParamKind::OMP_Uniform) 421353940Sdim .Default(VFParamKind::Unknown); 422353940Sdim 423353940Sdim if (ParamKind != VFParamKind::Unknown) 424353940Sdim return ParamKind; 425353940Sdim 426353940Sdim // This function should never be invoked with an invalid input. 427353940Sdim llvm_unreachable("This fuction should be invoken only on parameters" 428353940Sdim " that have a textual representation in the mangled name" 429353940Sdim " of the Vector Function ABI"); 430353940Sdim} 431