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 VF = 0; 74 IsScalable = true; 75 return ParseRet::OK; 76 } 77 78 if (ParseString.consumeInteger(10, VF)) 79 return ParseRet::Error; 80 81 IsScalable = false; 82 return ParseRet::OK; 83 } 84 85 /// The function looks for the following strings at the beginning of 86 /// the input string `ParseString`: 87 /// 88 /// <token> <number> 89 /// 90 /// On success, it removes the parsed parameter from `ParseString`, 91 /// sets `PKind` to the correspondent enum value, sets `Pos` to 92 /// <number>, and return success. On a syntax error, it return a 93 /// parsing error. If nothing is parsed, it returns None. 94 /// 95 /// The function expects <token> to be one of "ls", "Rs", "Us" or 96 /// "Ls". 97 ParseRet tryParseLinearTokenWithRuntimeStep(StringRef &ParseString, 98 VFParamKind &PKind, int &Pos, 99 const StringRef Token) { 100 if (ParseString.consume_front(Token)) { 101 PKind = VFABI::getVFParamKindFromString(Token); 102 if (ParseString.consumeInteger(10, Pos)) 103 return ParseRet::Error; 104 return ParseRet::OK; 105 } 106 107 return ParseRet::None; 108 } 109 110 /// The function looks for the following stringt at the beginning of 111 /// the input string `ParseString`: 112 /// 113 /// <token> <number> 114 /// 115 /// <token> is one of "ls", "Rs", "Us" or "Ls". 116 /// 117 /// On success, it removes the parsed parameter from `ParseString`, 118 /// sets `PKind` to the correspondent enum value, sets `StepOrPos` to 119 /// <number>, and return success. On a syntax error, it return a 120 /// parsing error. If nothing is parsed, it returns None. 121 ParseRet tryParseLinearWithRuntimeStep(StringRef &ParseString, 122 VFParamKind &PKind, int &StepOrPos) { 123 ParseRet Ret; 124 125 // "ls" <RuntimeStepPos> 126 Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "ls"); 127 if (Ret != ParseRet::None) 128 return Ret; 129 130 // "Rs" <RuntimeStepPos> 131 Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Rs"); 132 if (Ret != ParseRet::None) 133 return Ret; 134 135 // "Ls" <RuntimeStepPos> 136 Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Ls"); 137 if (Ret != ParseRet::None) 138 return Ret; 139 140 // "Us" <RuntimeStepPos> 141 Ret = tryParseLinearTokenWithRuntimeStep(ParseString, PKind, StepOrPos, "Us"); 142 if (Ret != ParseRet::None) 143 return Ret; 144 145 return ParseRet::None; 146 } 147 148 /// The function looks for the following strings at the beginning of 149 /// the input string `ParseString`: 150 /// 151 /// <token> {"n"} <number> 152 /// 153 /// On success, it removes the parsed parameter from `ParseString`, 154 /// sets `PKind` to the correspondent enum value, sets `LinearStep` to 155 /// <number>, and return success. On a syntax error, it return a 156 /// parsing error. If nothing is parsed, it returns None. 157 /// 158 /// The function expects <token> to be one of "l", "R", "U" or 159 /// "L". 160 ParseRet tryParseCompileTimeLinearToken(StringRef &ParseString, 161 VFParamKind &PKind, int &LinearStep, 162 const StringRef Token) { 163 if (ParseString.consume_front(Token)) { 164 PKind = VFABI::getVFParamKindFromString(Token); 165 const bool Negate = ParseString.consume_front("n"); 166 if (ParseString.consumeInteger(10, LinearStep)) 167 LinearStep = 1; 168 if (Negate) 169 LinearStep *= -1; 170 return ParseRet::OK; 171 } 172 173 return ParseRet::None; 174 } 175 176 /// The function looks for the following strings at the beginning of 177 /// the input string `ParseString`: 178 /// 179 /// ["l" | "R" | "U" | "L"] {"n"} <number> 180 /// 181 /// On success, it removes the parsed parameter from `ParseString`, 182 /// sets `PKind` to the correspondent enum value, sets `LinearStep` to 183 /// <number>, and return success. On a syntax error, it return a 184 /// parsing error. If nothing is parsed, it returns None. 185 ParseRet tryParseLinearWithCompileTimeStep(StringRef &ParseString, 186 VFParamKind &PKind, int &StepOrPos) { 187 // "l" {"n"} <CompileTimeStep> 188 if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "l") == 189 ParseRet::OK) 190 return ParseRet::OK; 191 192 // "R" {"n"} <CompileTimeStep> 193 if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "R") == 194 ParseRet::OK) 195 return ParseRet::OK; 196 197 // "L" {"n"} <CompileTimeStep> 198 if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "L") == 199 ParseRet::OK) 200 return ParseRet::OK; 201 202 // "U" {"n"} <CompileTimeStep> 203 if (tryParseCompileTimeLinearToken(ParseString, PKind, StepOrPos, "U") == 204 ParseRet::OK) 205 return ParseRet::OK; 206 207 return ParseRet::None; 208 } 209 210 /// The function looks for the following strings at the beginning of 211 /// the input string `ParseString`: 212 /// 213 /// "u" <number> 214 /// 215 /// On success, it removes the parsed parameter from `ParseString`, 216 /// sets `PKind` to the correspondent enum value, sets `Pos` to 217 /// <number>, and return success. On a syntax error, it return a 218 /// parsing error. If nothing is parsed, it returns None. 219 ParseRet tryParseUniform(StringRef &ParseString, VFParamKind &PKind, int &Pos) { 220 // "u" <Pos> 221 const char *UniformToken = "u"; 222 if (ParseString.consume_front(UniformToken)) { 223 PKind = VFABI::getVFParamKindFromString(UniformToken); 224 if (ParseString.consumeInteger(10, Pos)) 225 return ParseRet::Error; 226 227 return ParseRet::OK; 228 } 229 return ParseRet::None; 230 } 231 232 /// Looks into the <parameters> part of the mangled name in search 233 /// for valid paramaters at the beginning of the string 234 /// `ParseString`. 235 /// 236 /// On success, it removes the parsed parameter from `ParseString`, 237 /// sets `PKind` to the correspondent enum value, sets `StepOrPos` 238 /// accordingly, and return success. On a syntax error, it return a 239 /// parsing error. If nothing is parsed, it returns None. 240 ParseRet tryParseParameter(StringRef &ParseString, VFParamKind &PKind, 241 int &StepOrPos) { 242 if (ParseString.consume_front("v")) { 243 PKind = VFParamKind::Vector; 244 StepOrPos = 0; 245 return ParseRet::OK; 246 } 247 248 const ParseRet HasLinearRuntime = 249 tryParseLinearWithRuntimeStep(ParseString, PKind, StepOrPos); 250 if (HasLinearRuntime != ParseRet::None) 251 return HasLinearRuntime; 252 253 const ParseRet HasLinearCompileTime = 254 tryParseLinearWithCompileTimeStep(ParseString, PKind, StepOrPos); 255 if (HasLinearCompileTime != ParseRet::None) 256 return HasLinearCompileTime; 257 258 const ParseRet HasUniform = tryParseUniform(ParseString, PKind, StepOrPos); 259 if (HasUniform != ParseRet::None) 260 return HasUniform; 261 262 return ParseRet::None; 263 } 264 265 /// Looks into the <parameters> part of the mangled name in search 266 /// of a valid 'aligned' clause. The function should be invoked 267 /// after parsing a parameter via `tryParseParameter`. 268 /// 269 /// On success, it removes the parsed parameter from `ParseString`, 270 /// sets `PKind` to the correspondent enum value, sets `StepOrPos` 271 /// accordingly, and return success. On a syntax error, it return a 272 /// parsing error. If nothing is parsed, it returns None. 273 ParseRet tryParseAlign(StringRef &ParseString, Align &Alignment) { 274 uint64_t Val; 275 // "a" <number> 276 if (ParseString.consume_front("a")) { 277 if (ParseString.consumeInteger(10, Val)) 278 return ParseRet::Error; 279 280 if (!isPowerOf2_64(Val)) 281 return ParseRet::Error; 282 283 Alignment = Align(Val); 284 285 return ParseRet::OK; 286 } 287 288 return ParseRet::None; 289 } 290 } // namespace 291 292 // Format of the ABI name: 293 // _ZGV<isa><mask><vlen><parameters>_<scalarname>[(<redirection>)] 294 Optional<VFInfo> VFABI::tryDemangleForVFABI(StringRef MangledName) { 295 const StringRef OriginalName = MangledName; 296 // Assume there is no custom name <redirection>, and therefore the 297 // vector name consists of 298 // _ZGV<isa><mask><vlen><parameters>_<scalarname>. 299 StringRef VectorName = MangledName; 300 301 // Parse the fixed size part of the manled name 302 if (!MangledName.consume_front("_ZGV")) 303 return None; 304 305 // Extract ISA. An unknow ISA is also supported, so we accept all 306 // values. 307 VFISAKind ISA; 308 if (tryParseISA(MangledName, ISA) != ParseRet::OK) 309 return None; 310 311 // Extract <mask>. 312 bool IsMasked; 313 if (tryParseMask(MangledName, IsMasked) != ParseRet::OK) 314 return None; 315 316 // Parse the variable size, starting from <vlen>. 317 unsigned VF; 318 bool IsScalable; 319 if (tryParseVLEN(MangledName, VF, IsScalable) != ParseRet::OK) 320 return None; 321 322 // Parse the <parameters>. 323 ParseRet ParamFound; 324 SmallVector<VFParameter, 8> Parameters; 325 do { 326 const unsigned ParameterPos = Parameters.size(); 327 VFParamKind PKind; 328 int StepOrPos; 329 ParamFound = tryParseParameter(MangledName, PKind, StepOrPos); 330 331 // Bail off if there is a parsing error in the parsing of the parameter. 332 if (ParamFound == ParseRet::Error) 333 return None; 334 335 if (ParamFound == ParseRet::OK) { 336 Align Alignment; 337 // Look for the alignment token "a <number>". 338 const ParseRet AlignFound = tryParseAlign(MangledName, Alignment); 339 // Bail off if there is a syntax error in the align token. 340 if (AlignFound == ParseRet::Error) 341 return None; 342 343 // Add the parameter. 344 Parameters.push_back({ParameterPos, PKind, StepOrPos, Alignment}); 345 } 346 } while (ParamFound == ParseRet::OK); 347 348 // A valid MangledName must have at least one valid entry in the 349 // <parameters>. 350 if (Parameters.empty()) 351 return None; 352 353 // Check for the <scalarname> and the optional <redirection>, which 354 // are separated from the prefix with "_" 355 if (!MangledName.consume_front("_")) 356 return None; 357 358 // The rest of the string must be in the format: 359 // <scalarname>[(<redirection>)] 360 const StringRef ScalarName = 361 MangledName.take_while([](char In) { return In != '('; }); 362 363 if (ScalarName.empty()) 364 return None; 365 366 // Reduce MangledName to [(<redirection>)]. 367 MangledName = MangledName.ltrim(ScalarName); 368 // Find the optional custom name redirection. 369 if (MangledName.consume_front("(")) { 370 if (!MangledName.consume_back(")")) 371 return None; 372 // Update the vector variant with the one specified by the user. 373 VectorName = MangledName; 374 // If the vector name is missing, bail out. 375 if (VectorName.empty()) 376 return None; 377 } 378 379 // LLVM internal mapping via the TargetLibraryInfo (TLI) must be 380 // redirected to an existing name. 381 if (ISA == VFISAKind::LLVM && VectorName == OriginalName) 382 return None; 383 384 // When <mask> is "M", we need to add a parameter that is used as 385 // global predicate for the function. 386 if (IsMasked) { 387 const unsigned Pos = Parameters.size(); 388 Parameters.push_back({Pos, VFParamKind::GlobalPredicate}); 389 } 390 391 // Asserts for parameters of type `VFParamKind::GlobalPredicate`, as 392 // prescribed by the Vector Function ABI specifications supported by 393 // this parser: 394 // 1. Uniqueness. 395 // 2. Must be the last in the parameter list. 396 const auto NGlobalPreds = std::count_if( 397 Parameters.begin(), Parameters.end(), [](const VFParameter PK) { 398 return PK.ParamKind == VFParamKind::GlobalPredicate; 399 }); 400 assert(NGlobalPreds < 2 && "Cannot have more than one global predicate."); 401 if (NGlobalPreds) 402 assert(Parameters.back().ParamKind == VFParamKind::GlobalPredicate && 403 "The global predicate must be the last parameter"); 404 405 const VFShape Shape({VF, IsScalable, Parameters}); 406 return VFInfo({Shape, ScalarName, VectorName, ISA}); 407 } 408 409 VFParamKind VFABI::getVFParamKindFromString(const StringRef Token) { 410 const VFParamKind ParamKind = StringSwitch<VFParamKind>(Token) 411 .Case("v", VFParamKind::Vector) 412 .Case("l", VFParamKind::OMP_Linear) 413 .Case("R", VFParamKind::OMP_LinearRef) 414 .Case("L", VFParamKind::OMP_LinearVal) 415 .Case("U", VFParamKind::OMP_LinearUVal) 416 .Case("ls", VFParamKind::OMP_LinearPos) 417 .Case("Ls", VFParamKind::OMP_LinearValPos) 418 .Case("Rs", VFParamKind::OMP_LinearRefPos) 419 .Case("Us", VFParamKind::OMP_LinearUValPos) 420 .Case("u", VFParamKind::OMP_Uniform) 421 .Default(VFParamKind::Unknown); 422 423 if (ParamKind != VFParamKind::Unknown) 424 return ParamKind; 425 426 // This function should never be invoked with an invalid input. 427 llvm_unreachable("This fuction should be invoken only on parameters" 428 " that have a textual representation in the mangled name" 429 " of the Vector Function ABI"); 430 } 431