1 //===- VFABIDemangling.cpp - Vector Function ABI demangling utilities. ---===// 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/ADT/SmallSet.h" 10 #include "llvm/ADT/SmallString.h" 11 #include "llvm/Analysis/VectorUtils.h" 12 13 using namespace llvm; 14 15 namespace { 16 /// Utilities for the Vector Function ABI name parser. 17 18 /// Return types for the parser functions. 19 enum class ParseRet { 20 OK, // Found. 21 None, // Not found. 22 Error // Syntax error. 23 }; 24 25 /// Extracts the `<isa>` information from the mangled string, and 26 /// sets the `ISA` accordingly. 27 ParseRet tryParseISA(StringRef &MangledName, VFISAKind &ISA) { 28 if (MangledName.empty()) 29 return ParseRet::Error; 30 31 if (MangledName.startswith(VFABI::_LLVM_)) { 32 MangledName = MangledName.drop_front(strlen(VFABI::_LLVM_)); 33 ISA = VFISAKind::LLVM; 34 } else { 35 ISA = StringSwitch<VFISAKind>(MangledName.take_front(1)) 36 .Case("n", VFISAKind::AdvancedSIMD) 37 .Case("s", VFISAKind::SVE) 38 .Case("b", VFISAKind::SSE) 39 .Case("c", VFISAKind::AVX) 40 .Case("d", VFISAKind::AVX2) 41 .Case("e", VFISAKind::AVX512) 42 .Default(VFISAKind::Unknown); 43 MangledName = MangledName.drop_front(1); 44 } 45 46 return ParseRet::OK; 47 } 48 49 /// Extracts the `<mask>` information from the mangled string, and 50 /// sets `IsMasked` accordingly. The input string `MangledName` is 51 /// left unmodified. 52 ParseRet tryParseMask(StringRef &MangledName, bool &IsMasked) { 53 if (MangledName.consume_front("M")) { 54 IsMasked = true; 55 return ParseRet::OK; 56 } 57 58 if (MangledName.consume_front("N")) { 59 IsMasked = false; 60 return ParseRet::OK; 61 } 62 63 return ParseRet::Error; 64 } 65 66 /// Extract the `<vlen>` information from the mangled string, and 67 /// sets `VF` accordingly. A `<vlen> == "x"` token is interpreted as a scalable 68 /// vector length. On success, the `<vlen>` token is removed from 69 /// the input string `ParseString`. 70 /// 71 ParseRet tryParseVLEN(StringRef &ParseString, unsigned &VF, bool &IsScalable) { 72 if (ParseString.consume_front("x")) { 73 // Set VF to 0, to be later adjusted to a value grater than zero 74 // by looking at the signature of the vector function with 75 // `getECFromSignature`. 76 VF = 0; 77 IsScalable = true; 78 return ParseRet::OK; 79 } 80 81 if (ParseString.consumeInteger(10, VF)) 82 return ParseRet::Error; 83 84 // The token `0` is invalid for VLEN. 85 if (VF == 0) 86 return ParseRet::Error; 87 88 IsScalable = false; 89 return ParseRet::OK; 90 } 91 92 /// The function looks for the following strings at the beginning of 93 /// the input string `ParseString`: 94 /// 95 /// <token> <number> 96 /// 97 /// On success, it removes the parsed parameter from `ParseString`, 98 /// sets `PKind` to the correspondent enum value, sets `Pos` to 99 /// <number>, and return success. On a syntax error, it return a 100 /// parsing error. If nothing is parsed, it returns None. 101 /// 102 /// The function expects <token> to be one of "ls", "Rs", "Us" or 103 /// "Ls". 104 ParseRet tryParseLinearTokenWithRuntimeStep(StringRef &ParseString, 105 VFParamKind &PKind, int &Pos, 106 const StringRef Token) { 107 if (ParseString.consume_front(Token)) { 108 PKind = VFABI::getVFParamKindFromString(Token); 109 if (ParseString.consumeInteger(10, Pos)) 110 return ParseRet::Error; 111 return ParseRet::OK; 112 } 113 114 return ParseRet::None; 115 } 116 117 /// The function looks for the following stringt at the beginning of 118 /// the input string `ParseString`: 119 /// 120 /// <token> <number> 121 /// 122 /// <token> is one of "ls", "Rs", "Us" or "Ls". 123 /// 124 /// On success, it removes the parsed parameter from `ParseString`, 125 /// sets `PKind` to the correspondent enum value, sets `StepOrPos` to 126 /// <number>, and return success. On a syntax error, it return a 127 /// parsing error. If nothing is parsed, it returns None. 128 ParseRet tryParseLinearWithRuntimeStep(StringRef &ParseString, 129 VFParamKind &PKind, int &StepOrPos) { 130 ParseRet Ret; 131 132 // "ls" <RuntimeStepPos> 133 Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "ls"); 134 if (Ret != ParseRet::None) 135 return Ret; 136 137 // "Rs" <RuntimeStepPos> 138 Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Rs"); 139 if (Ret != ParseRet::None) 140 return Ret; 141 142 // "Ls" <RuntimeStepPos> 143 Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Ls"); 144 if (Ret != ParseRet::None) 145 return Ret; 146 147 // "Us" <RuntimeStepPos> 148 Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Us"); 149 if (Ret != ParseRet::None) 150 return Ret; 151 152 return ParseRet::None; 153 } 154 155 /// The function looks for the following strings at the beginning of 156 /// the input string `ParseString`: 157 /// 158 /// <token> {"n"} <number> 159 /// 160 /// On success, it removes the parsed parameter from `ParseString`, 161 /// sets `PKind` to the correspondent enum value, sets `LinearStep` to 162 /// <number>, and return success. On a syntax error, it return a 163 /// parsing error. If nothing is parsed, it returns None. 164 /// 165 /// The function expects <token> to be one of "l", "R", "U" or 166 /// "L". 167 ParseRet tryParseCompileTimeLinearToken(StringRef &ParseString, 168 VFParamKind &PKind, int &LinearStep, 169 const StringRef Token) { 170 if (ParseString.consume_front(Token)) { 171 PKind = VFABI::getVFParamKindFromString(Token); 172 const bool Negate = ParseString.consume_front("n"); 173 if (ParseString.consumeInteger(10, LinearStep)) 174 LinearStep = 1; 175 if (Negate) 176 LinearStep *= -1; 177 return ParseRet::OK; 178 } 179 180 return ParseRet::None; 181 } 182 183 /// The function looks for the following strings at the beginning of 184 /// the input string `ParseString`: 185 /// 186 /// ["l" | "R" | "U" | "L"] {"n"} <number> 187 /// 188 /// On success, it removes the parsed parameter from `ParseString`, 189 /// sets `PKind` to the correspondent enum value, sets `LinearStep` to 190 /// <number>, and return success. On a syntax error, it return a 191 /// parsing error. If nothing is parsed, it returns None. 192 ParseRet tryParseLinearWithCompileTimeStep(StringRef &ParseString, 193 VFParamKind &PKind, int &StepOrPos) { 194 // "l" {"n"} <CompileTimeStep> 195 if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "l") == 196 ParseRet::OK) 197 return ParseRet::OK; 198 199 // "R" {"n"} <CompileTimeStep> 200 if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "R") == 201 ParseRet::OK) 202 return ParseRet::OK; 203 204 // "L" {"n"} <CompileTimeStep> 205 if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "L") == 206 ParseRet::OK) 207 return ParseRet::OK; 208 209 // "U" {"n"} <CompileTimeStep> 210 if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "U") == 211 ParseRet::OK) 212 return ParseRet::OK; 213 214 return ParseRet::None; 215 } 216 217 /// The function looks for the following strings at the beginning of 218 /// the input string `ParseString`: 219 /// 220 /// "u" <number> 221 /// 222 /// On success, it removes the parsed parameter from `ParseString`, 223 /// sets `PKind` to the correspondent enum value, sets `Pos` to 224 /// <number>, and return success. On a syntax error, it return a 225 /// parsing error. If nothing is parsed, it returns None. 226 ParseRet tryParseUniform(StringRef &ParseString, VFParamKind &PKind, int &Pos) { 227 // "u" <Pos> 228 const char *UniformToken = "u"; 229 if (ParseString.consume_front(UniformToken)) { 230 PKind = VFABI::getVFParamKindFromString(UniformToken); 231 if (ParseString.consumeInteger(10, Pos)) 232 return ParseRet::Error; 233 234 return ParseRet::OK; 235 } 236 return ParseRet::None; 237 } 238 239 /// Looks into the <parameters> part of the mangled name in search 240 /// for valid paramaters at the beginning of the string 241 /// `ParseString`. 242 /// 243 /// On success, it removes the parsed parameter from `ParseString`, 244 /// sets `PKind` to the correspondent enum value, sets `StepOrPos` 245 /// accordingly, and return success. On a syntax error, it return a 246 /// parsing error. If nothing is parsed, it returns None. 247 ParseRet tryParseParameter(StringRef &ParseString, VFParamKind &PKind, 248 int &StepOrPos) { 249 if (ParseString.consume_front("v")) { 250 PKind = VFParamKind::Vector; 251 StepOrPos = 0; 252 return ParseRet::OK; 253 } 254 255 const ParseRet HasLinearRuntime = 256 tryParseLinearWithRuntimeStep(ParseString, PKind, StepOrPos); 257 if (HasLinearRuntime != ParseRet::None) 258 return HasLinearRuntime; 259 260 const ParseRet HasLinearCompileTime = 261 tryParseLinearWithCompileTimeStep(ParseString, PKind, StepOrPos); 262 if (HasLinearCompileTime != ParseRet::None) 263 return HasLinearCompileTime; 264 265 const ParseRet HasUniform = tryParseUniform(ParseString, PKind, StepOrPos); 266 if (HasUniform != ParseRet::None) 267 return HasUniform; 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 None. 280 ParseRet tryParseAlign(StringRef &ParseString, Align &Alignment) { 281 uint64_t Val; 282 // "a" <number> 283 if (ParseString.consume_front("a")) { 284 if (ParseString.consumeInteger(10, Val)) 285 return ParseRet::Error; 286 287 if (!isPowerOf2_64(Val)) 288 return ParseRet::Error; 289 290 Alignment = Align(Val); 291 292 return ParseRet::OK; 293 } 294 295 return ParseRet::None; 296 } 297 #ifndef NDEBUG 298 // Verify the assumtion that all vectors in the signature of a vector 299 // function have the same number of elements. 300 bool verifyAllVectorsHaveSameWidth(FunctionType *Signature) { 301 SmallVector<VectorType *, 2> VecTys; 302 if (auto *RetTy = dyn_cast<VectorType>(Signature->getReturnType())) 303 VecTys.push_back(RetTy); 304 for (auto *Ty : Signature->params()) 305 if (auto *VTy = dyn_cast<VectorType>(Ty)) 306 VecTys.push_back(VTy); 307 308 if (VecTys.size() <= 1) 309 return true; 310 311 assert(VecTys.size() > 1 && "Invalid number of elements."); 312 const ElementCount EC = VecTys[0]->getElementCount(); 313 return llvm::all_of( 314 llvm::make_range(VecTys.begin() + 1, VecTys.end()), 315 [&EC](VectorType *VTy) { return (EC == VTy->getElementCount()); }); 316 } 317 318 #endif // NDEBUG 319 320 // Extract the VectorizationFactor from a given function signature, 321 // under the assumtion that all vectors have the same number of 322 // elements, i.e. same ElementCount.Min. 323 ElementCount getECFromSignature(FunctionType *Signature) { 324 assert(verifyAllVectorsHaveSameWidth(Signature) && 325 "Invalid vector signature."); 326 327 if (auto *RetTy = dyn_cast<VectorType>(Signature->getReturnType())) 328 return RetTy->getElementCount(); 329 for (auto *Ty : Signature->params()) 330 if (auto *VTy = dyn_cast<VectorType>(Ty)) 331 return VTy->getElementCount(); 332 333 return ElementCount(/*Min=*/1, /*Scalable=*/false); 334 } 335 } // namespace 336 337 // Format of the ABI name: 338 // _ZGV<isa><mask><vlen><parameters>_<scalarname>[(<redirection>)] 339 Optional<VFInfo> VFABI::tryDemangleForVFABI(StringRef MangledName, 340 const Module &M) { 341 const StringRef OriginalName = MangledName; 342 // Assume there is no custom name <redirection>, and therefore the 343 // vector name consists of 344 // _ZGV<isa><mask><vlen><parameters>_<scalarname>. 345 StringRef VectorName = MangledName; 346 347 // Parse the fixed size part of the manled name 348 if (!MangledName.consume_front("_ZGV")) 349 return None; 350 351 // Extract ISA. An unknow ISA is also supported, so we accept all 352 // values. 353 VFISAKind ISA; 354 if (tryParseISA(MangledName, ISA) != ParseRet::OK) 355 return None; 356 357 // Extract <mask>. 358 bool IsMasked; 359 if (tryParseMask(MangledName, IsMasked) != ParseRet::OK) 360 return None; 361 362 // Parse the variable size, starting from <vlen>. 363 unsigned VF; 364 bool IsScalable; 365 if (tryParseVLEN(MangledName, VF, IsScalable) != ParseRet::OK) 366 return None; 367 368 // Parse the <parameters>. 369 ParseRet ParamFound; 370 SmallVector<VFParameter, 8> Parameters; 371 do { 372 const unsigned ParameterPos = Parameters.size(); 373 VFParamKind PKind; 374 int StepOrPos; 375 ParamFound = tryParseParameter(MangledName, PKind, StepOrPos); 376 377 // Bail off if there is a parsing error in the parsing of the parameter. 378 if (ParamFound == ParseRet::Error) 379 return None; 380 381 if (ParamFound == ParseRet::OK) { 382 Align Alignment; 383 // Look for the alignment token "a <number>". 384 const ParseRet AlignFound = tryParseAlign(MangledName, Alignment); 385 // Bail off if there is a syntax error in the align token. 386 if (AlignFound == ParseRet::Error) 387 return None; 388 389 // Add the parameter. 390 Parameters.push_back({ParameterPos, PKind, StepOrPos, Alignment}); 391 } 392 } while (ParamFound == ParseRet::OK); 393 394 // A valid MangledName must have at least one valid entry in the 395 // <parameters>. 396 if (Parameters.empty()) 397 return None; 398 399 // Check for the <scalarname> and the optional <redirection>, which 400 // are separated from the prefix with "_" 401 if (!MangledName.consume_front("_")) 402 return None; 403 404 // The rest of the string must be in the format: 405 // <scalarname>[(<redirection>)] 406 const StringRef ScalarName = 407 MangledName.take_while([](char In) { return In != '('; }); 408 409 if (ScalarName.empty()) 410 return None; 411 412 // Reduce MangledName to [(<redirection>)]. 413 MangledName = MangledName.ltrim(ScalarName); 414 // Find the optional custom name redirection. 415 if (MangledName.consume_front("(")) { 416 if (!MangledName.consume_back(")")) 417 return None; 418 // Update the vector variant with the one specified by the user. 419 VectorName = MangledName; 420 // If the vector name is missing, bail out. 421 if (VectorName.empty()) 422 return None; 423 } 424 425 // LLVM internal mapping via the TargetLibraryInfo (TLI) must be 426 // redirected to an existing name. 427 if (ISA == VFISAKind::LLVM && VectorName == OriginalName) 428 return None; 429 430 // When <mask> is "M", we need to add a parameter that is used as 431 // global predicate for the function. 432 if (IsMasked) { 433 const unsigned Pos = Parameters.size(); 434 Parameters.push_back({Pos, VFParamKind::GlobalPredicate}); 435 } 436 437 // Asserts for parameters of type `VFParamKind::GlobalPredicate`, as 438 // prescribed by the Vector Function ABI specifications supported by 439 // this parser: 440 // 1. Uniqueness. 441 // 2. Must be the last in the parameter list. 442 const auto NGlobalPreds = std::count_if( 443 Parameters.begin(), Parameters.end(), [](const VFParameter PK) { 444 return PK.ParamKind == VFParamKind::GlobalPredicate; 445 }); 446 assert(NGlobalPreds < 2 && "Cannot have more than one global predicate."); 447 if (NGlobalPreds) 448 assert(Parameters.back().ParamKind == VFParamKind::GlobalPredicate && 449 "The global predicate must be the last parameter"); 450 451 // Adjust the VF for scalable signatures. The EC.Min is not encoded 452 // in the name of the function, but it is encoded in the IR 453 // signature of the function. We need to extract this information 454 // because it is needed by the loop vectorizer, which reasons in 455 // terms of VectorizationFactor or ElementCount. In particular, we 456 // need to make sure that the VF field of the VFShape class is never 457 // set to 0. 458 if (IsScalable) { 459 const Function *F = M.getFunction(VectorName); 460 // The declaration of the function must be present in the module 461 // to be able to retrieve its signature. 462 if (!F) 463 return None; 464 const ElementCount EC = getECFromSignature(F->getFunctionType()); 465 VF = EC.Min; 466 } 467 468 // Sanity checks. 469 // 1. We don't accept a zero lanes vectorization factor. 470 // 2. We don't accept the demangling if the vector function is not 471 // present in the module. 472 if (VF == 0) 473 return None; 474 if (!M.getFunction(VectorName)) 475 return None; 476 477 const VFShape Shape({VF, IsScalable, Parameters}); 478 return VFInfo({Shape, std::string(ScalarName), std::string(VectorName), ISA}); 479 } 480 481 VFParamKind VFABI::getVFParamKindFromString(const StringRef Token) { 482 const VFParamKind ParamKind = StringSwitch<VFParamKind>(Token) 483 .Case("v", VFParamKind::Vector) 484 .Case("l", VFParamKind::OMP_Linear) 485 .Case("R", VFParamKind::OMP_LinearRef) 486 .Case("L", VFParamKind::OMP_LinearVal) 487 .Case("U", VFParamKind::OMP_LinearUVal) 488 .Case("ls", VFParamKind::OMP_LinearPos) 489 .Case("Ls", VFParamKind::OMP_LinearValPos) 490 .Case("Rs", VFParamKind::OMP_LinearRefPos) 491 .Case("Us", VFParamKind::OMP_LinearUValPos) 492 .Case("u", VFParamKind::OMP_Uniform) 493 .Default(VFParamKind::Unknown); 494 495 if (ParamKind != VFParamKind::Unknown) 496 return ParamKind; 497 498 // This function should never be invoked with an invalid input. 499 llvm_unreachable("This fuction should be invoken only on parameters" 500 " that have a textual representation in the mangled name" 501 " of the Vector Function ABI"); 502 } 503