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