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 13using namespace llvm; 14 15namespace { 16/// Utilities for the Vector Function ABI name parser. 17 18/// Return types for the parser functions. 19enum 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. 27ParseRet 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. 52ParseRet 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/// 71ParseRet 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". 97ParseRet 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. 121ParseRet 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". 160ParseRet 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. 185ParseRet 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. 219ParseRet 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. 240ParseRet 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. 273ParseRet 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>)] 294Optional<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 409VFParamKind 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