VFABIDemangling.cpp 17 KB

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