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