brintos

brintos / llvm-project-archived public Read only

0
0
Text · 30.4 KiB · 8c7f9f7 Raw
832 lines · cpp
1//===- EnumsGen.cpp - MLIR enum utility generator -------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8//9// EnumsGen generates common utility functions for enums.10//11//===----------------------------------------------------------------------===//12 13#include "FormatGen.h"14#include "mlir/TableGen/Attribute.h"15#include "mlir/TableGen/EnumInfo.h"16#include "mlir/TableGen/Format.h"17#include "mlir/TableGen/GenInfo.h"18#include "llvm/ADT/BitVector.h"19#include "llvm/ADT/SmallVector.h"20#include "llvm/ADT/StringExtras.h"21#include "llvm/Support/FormatVariadic.h"22#include "llvm/Support/raw_ostream.h"23#include "llvm/TableGen/CodeGenHelpers.h"24#include "llvm/TableGen/Error.h"25#include "llvm/TableGen/Record.h"26#include "llvm/TableGen/TableGenBackend.h"27 28using llvm::formatv;29using llvm::isDigit;30using llvm::PrintFatalError;31using llvm::Record;32using llvm::RecordKeeper;33using namespace mlir;34using mlir::tblgen::Attribute;35using mlir::tblgen::EnumCase;36using mlir::tblgen::EnumInfo;37using mlir::tblgen::FmtContext;38using mlir::tblgen::tgfmt;39 40static std::string makeIdentifier(StringRef str) {41  if (!str.empty() && isDigit(static_cast<unsigned char>(str.front()))) {42    std::string newStr = std::string("_") + str.str();43    return newStr;44  }45  return str.str();46}47 48static void emitEnumClass(const Record &enumDef, StringRef enumName,49                          StringRef underlyingType, StringRef description,50                          ArrayRef<EnumCase> enumerants, raw_ostream &os) {51  os << "// " << description << "\n";52  os << "enum class " << enumName;53 54  if (!underlyingType.empty())55    os << " : " << underlyingType;56  os << " {\n";57 58  for (const EnumCase &enumerant : enumerants) {59    auto symbol = makeIdentifier(enumerant.getSymbol());60    auto value = enumerant.getValue();61    if (value >= 0)62      os << formatv("  {0} = {1},\n", symbol, value);63    else64      os << formatv("  {0},\n", symbol);65  }66  os << "};\n\n";67}68 69static void emitParserPrinter(const EnumInfo &enumInfo, StringRef qualName,70                              StringRef cppNamespace, raw_ostream &os) {71  std::optional<Attribute> enumAttrInfo = enumInfo.asEnumAttr();72  if (enumInfo.getUnderlyingType().empty() ||73      (enumAttrInfo && enumAttrInfo->getConstBuilderTemplate().empty()))74    return;75  auto cases = enumInfo.getAllCases();76 77  // Check which cases shouldn't be printed using a keyword.78  llvm::BitVector nonKeywordCases(cases.size());79  std::string casesList;80  llvm::raw_string_ostream caseListOs(casesList);81  caseListOs << "[";82  llvm::interleaveComma(llvm::enumerate(cases), caseListOs,83                        [&](auto enumerant) {84                          StringRef name = enumerant.value().getStr();85                          if (!mlir::tblgen::canFormatStringAsKeyword(name)) {86                            nonKeywordCases.set(enumerant.index());87                            caseListOs << "\\\"" << name << "\\\"";88                          }89                          caseListOs << name;90                        });91  caseListOs << "]";92 93  // Generate the parser and the start of the printer for the enum, excluding94  // non-quoted bit enums.95  const char *parsedAndPrinterStart = R"(96namespace mlir {97template <typename T, typename>98struct FieldParser;99 100template<>101struct FieldParser<{0}, {0}> {{102  template <typename ParserT>103  static FailureOr<{0}> parse(ParserT &parser) {{104    // Parse the keyword/string containing the enum.105    std::string enumKeyword;106    auto loc = parser.getCurrentLocation();107    if (failed(parser.parseOptionalKeywordOrString(&enumKeyword)))108      return parser.emitError(loc, "expected keyword for {2}");109 110    // Symbolize the keyword.111    if (::std::optional<{0}> attr = {1}::symbolizeEnum<{0}>(enumKeyword))112      return *attr;113    return parser.emitError(loc, "expected one of {3} for {2}, got: ") << enumKeyword;114  }115};116 117/// Support for std::optional, useful in attribute/type definition where the enum is118/// used as:119///120///    let parameters = (ins OptionalParameter<"std::optional<TheEnumName>">:$value);121template<>122struct FieldParser<std::optional<{0}>, std::optional<{0}>> {{123  template <typename ParserT>124  static FailureOr<std::optional<{0}>> parse(ParserT &parser) {{125    // Parse the keyword/string containing the enum.126    std::string enumKeyword;127    auto loc = parser.getCurrentLocation();128    if (failed(parser.parseOptionalKeywordOrString(&enumKeyword)))129      return std::optional<{0}>{{};130 131    // Symbolize the keyword.132    if (::std::optional<{0}> attr = {1}::symbolizeEnum<{0}>(enumKeyword))133      return attr;134    return parser.emitError(loc, "expected one of {3} for {2}, got: ") << enumKeyword;135  }136};137} // namespace mlir138 139namespace llvm {140inline ::llvm::raw_ostream &operator<<(::llvm::raw_ostream &p, {0} value) {{141  auto valueStr = stringifyEnum(value);142)";143 144  const char *parsedAndPrinterStartUnquotedBitEnum = R"(145  namespace mlir {146  template <typename T, typename>147  struct FieldParser;148 149  template<>150  struct FieldParser<{0}, {0}> {{151    template <typename ParserT>152    static FailureOr<{0}> parse(ParserT &parser) {{153      {0} flags = {{};154      do {{155        // Parse the keyword containing a part of the enum.156        ::llvm::StringRef enumKeyword;157        auto loc = parser.getCurrentLocation();158        if (failed(parser.parseOptionalKeyword(&enumKeyword))) {{159          return parser.emitError(loc, "expected keyword for {2}");160        }161 162        // Symbolize the keyword.163        if (::std::optional<{0}> flag = {1}::symbolizeEnum<{0}>(enumKeyword)) {{164          flags = flags | *flag;165        } else {{166          return parser.emitError(loc, "expected one of {3} for {2}, got: ") << enumKeyword;167        }168      } while (::mlir::succeeded(parser.{5}()));169      return flags;170    }171  };172 173  /// Support for std::optional, useful in attribute/type definition where the enum is174  /// used as:175  ///176  ///    let parameters = (ins OptionalParameter<"std::optional<TheEnumName>">:$value);177  template<>178  struct FieldParser<std::optional<{0}>, std::optional<{0}>> {{179    template <typename ParserT>180    static FailureOr<std::optional<{0}>> parse(ParserT &parser) {{181      {0} flags = {{};182      bool firstIter = true;183      do {{184        // Parse the keyword containing a part of the enum.185        ::llvm::StringRef enumKeyword;186        auto loc = parser.getCurrentLocation();187        if (failed(parser.parseOptionalKeyword(&enumKeyword))) {{188          if (firstIter)189            return std::optional<{0}>{{};190          return parser.emitError(loc, "expected keyword for {2} after '{4}'");191        }192        firstIter = false;193 194        // Symbolize the keyword.195        if (::std::optional<{0}> flag = {1}::symbolizeEnum<{0}>(enumKeyword)) {{196          flags = flags | *flag;197        } else {{198          return parser.emitError(loc, "expected one of {3} for {2}, got: ") << enumKeyword;199        }200      } while(::mlir::succeeded(parser.{5}()));201      return std::optional<{0}>{{flags};202    }203  };204  } // namespace mlir205 206  namespace llvm {207  inline ::llvm::raw_ostream &operator<<(::llvm::raw_ostream &p, {0} value) {{208    auto valueStr = stringifyEnum(value);209  )";210 211  bool isNewStyleBitEnum =212      enumInfo.isBitEnum() && !enumInfo.printBitEnumQuoted();213 214  if (isNewStyleBitEnum) {215    if (nonKeywordCases.any())216      return PrintFatalError(217          "bit enum " + qualName +218          " cannot be printed unquoted with cases that cannot be keywords");219    StringRef separator = enumInfo.getDef().getValueAsString("separator");220    StringRef parseSeparatorFn =221        llvm::StringSwitch<StringRef>(separator.trim())222            .Case("|", "parseOptionalVerticalBar")223            .Case(",", "parseOptionalComma")224            .Default("error, enum separator must be '|' or ','");225    os << formatv(parsedAndPrinterStartUnquotedBitEnum, qualName, cppNamespace,226                  enumInfo.getSummary(), casesList, separator,227                  parseSeparatorFn);228  } else {229    os << formatv(parsedAndPrinterStart, qualName, cppNamespace,230                  enumInfo.getSummary(), casesList);231  }232 233  // If all cases require a string, always wrap.234  if (nonKeywordCases.all()) {235    os << "  return p << '\"' << valueStr << '\"';\n"236          "}\n"237          "} // namespace llvm\n";238    return;239  }240 241  // If there are any cases that can't be used with a keyword, switch on the242  // case value to determine when to print in the string form.243  if (nonKeywordCases.any()) {244    os << "  switch (value) {\n";245    for (auto it : llvm::enumerate(cases)) {246      if (nonKeywordCases.test(it.index()))247        continue;248      StringRef symbol = it.value().getSymbol();249      os << llvm::formatv("  case {0}::{1}:\n", qualName,250                          makeIdentifier(symbol));251    }252    os << "    break;\n"253          "  default:\n"254          "    return p << '\"' << valueStr << '\"';\n"255          "  }\n";256 257    // If this is a bit enum, conservatively print the string form if the value258    // is not a power of two (i.e. not a single bit case) and not a known case.259    // Only do this if we're using the old-style parser that parses the enum as260    // one keyword, as opposed to the new form, where we can print the value261    // as-is.262  } else if (enumInfo.isBitEnum() && !isNewStyleBitEnum) {263    // Process the known multi-bit cases that use valid keywords.264    SmallVector<EnumCase *> validMultiBitCases;265    for (auto [index, caseVal] : llvm::enumerate(cases)) {266      uint64_t value = caseVal.getValue();267      if (value && !llvm::has_single_bit(value) && !nonKeywordCases.test(index))268        validMultiBitCases.push_back(&caseVal);269    }270    if (!validMultiBitCases.empty()) {271      os << "  switch (value) {\n";272      for (EnumCase *caseVal : validMultiBitCases) {273        StringRef symbol = caseVal->getSymbol();274        os << llvm::formatv("  case {0}::{1}:\n", qualName,275                            llvm::isDigit(symbol.front()) ? ("_" + symbol)276                                                          : symbol);277      }278      os << "    return p << valueStr;\n"279            "  default:\n"280            "    break;\n"281            "  }\n";282    }283 284    // All other multi-bit cases should be printed as strings.285    os << formatv("  auto underlyingValue = "286                  "static_cast<std::make_unsigned_t<{0}>>(value);\n",287                  qualName);288    os << "  if (underlyingValue && !llvm::has_single_bit(underlyingValue))\n"289          "    return p << '\"' << valueStr << '\"';\n";290  }291  os << "  return p << valueStr;\n"292        "}\n"293        "} // namespace llvm\n";294}295 296static void emitDenseMapInfo(StringRef qualName, std::string underlyingType,297                             StringRef cppNamespace, raw_ostream &os) {298  if (underlyingType.empty())299    underlyingType =300        std::string(formatv("std::underlying_type_t<{0}>", qualName));301 302  const char *const mapInfo = R"(303namespace llvm {304template<> struct DenseMapInfo<{0}> {{305  using StorageInfo = ::llvm::DenseMapInfo<{1}>;306 307  static inline {0} getEmptyKey() {{308    return static_cast<{0}>(StorageInfo::getEmptyKey());309  }310 311  static inline {0} getTombstoneKey() {{312    return static_cast<{0}>(StorageInfo::getTombstoneKey());313  }314 315  static unsigned getHashValue(const {0} &val) {{316    return StorageInfo::getHashValue(static_cast<{1}>(val));317  }318 319  static bool isEqual(const {0} &lhs, const {0} &rhs) {{320    return lhs == rhs;321  }322};323})";324  os << formatv(mapInfo, qualName, underlyingType);325  os << "\n\n";326}327 328static void emitMaxValueFn(const Record &enumDef, raw_ostream &os) {329  EnumInfo enumInfo(enumDef);330  StringRef maxEnumValFnName = enumInfo.getMaxEnumValFnName();331  auto enumerants = enumInfo.getAllCases();332 333  unsigned maxEnumVal = 0;334  for (const auto &enumerant : enumerants) {335    int64_t value = enumerant.getValue();336    // Avoid generating the max value function if there is an enumerant without337    // explicit value.338    if (value < 0)339      return;340 341    maxEnumVal = std::max(maxEnumVal, static_cast<unsigned>(value));342  }343 344  // Emit the function to return the max enum value345  os << formatv("inline constexpr unsigned {0}() {{\n", maxEnumValFnName);346  os << formatv("  return {0};\n", maxEnumVal);347  os << "}\n\n";348}349 350// Returns the EnumCase whose value is zero if exists; returns std::nullopt351// otherwise.352static std::optional<EnumCase>353getAllBitsUnsetCase(llvm::ArrayRef<EnumCase> cases) {354  for (auto attrCase : cases) {355    if (attrCase.getValue() == 0)356      return attrCase;357  }358  return std::nullopt;359}360 361// Emits the following inline function for bit enums:362//363// inline constexpr <enum-type> operator|(<enum-type> a, <enum-type> b);364// inline constexpr <enum-type> operator&(<enum-type> a, <enum-type> b);365// inline constexpr <enum-type> operator^(<enum-type> a, <enum-type> b);366// inline constexpr <enum-type> &operator|=(<enum-type> &a, <enum-type> b);367// inline constexpr <enum-type> &operator&=(<enum-type> &a, <enum-type> b);368// inline constexpr <enum-type> &operator^=(<enum-type> &a, <enum-type> b);369// inline constexpr <enum-type> operator~(<enum-type> bits);370// inline constexpr bool bitEnumContainsAll(<enum-type> bits, <enum-type> bit);371// inline constexpr bool bitEnumContainsAny(<enum-type> bits, <enum-type> bit);372// inline constexpr <enum-type> bitEnumClear(<enum-type> bits, <enum-type> bit);373// inline constexpr <enum-type> bitEnumSet(<enum-type> bits, <enum-type> bit,374// bool value=true);375static void emitOperators(const Record &enumDef, raw_ostream &os) {376  EnumInfo enumInfo(enumDef);377  StringRef enumName = enumInfo.getEnumClassName();378  std::string underlyingType = std::string(enumInfo.getUnderlyingType());379  int64_t validBits = enumDef.getValueAsInt("validBits");380  const char *const operators = R"(381inline constexpr {0} operator|({0} a, {0} b) {{382  return static_cast<{0}>(static_cast<{1}>(a) | static_cast<{1}>(b));383}384inline constexpr {0} operator&({0} a, {0} b) {{385  return static_cast<{0}>(static_cast<{1}>(a) & static_cast<{1}>(b));386}387inline constexpr {0} operator^({0} a, {0} b) {{388  return static_cast<{0}>(static_cast<{1}>(a) ^ static_cast<{1}>(b));389}390inline constexpr {0} &operator|=({0} &a, {0} b) {{391    return a = a | b;392}393inline constexpr {0} &operator&=({0} &a, {0} b) {{394    return a = a & b;395}396inline constexpr {0} &operator^=({0} &a, {0} b) {{397    return a = a ^ b;398}399inline constexpr {0} operator~({0} bits) {{400  // Ensure only bits that can be present in the enum are set401  return static_cast<{0}>(~static_cast<{1}>(bits) & static_cast<{1}>({2}u));402}403inline constexpr bool bitEnumContainsAll({0} bits, {0} bit) {{404  return (bits & bit) == bit;405}406inline constexpr bool bitEnumContainsAny({0} bits, {0} bit) {{407  return (static_cast<{1}>(bits) & static_cast<{1}>(bit)) != 0;408}409inline constexpr {0} bitEnumClear({0} bits, {0} bit) {{410  return bits & ~bit;411}412inline constexpr {0} bitEnumSet({0} bits, {0} bit, /*optional*/bool value=true) {{413  return value ? (bits | bit) : bitEnumClear(bits, bit);414}415  )";416  os << formatv(operators, enumName, underlyingType, validBits);417}418 419static void emitSymToStrFnForIntEnum(const Record &enumDef, raw_ostream &os) {420  EnumInfo enumInfo(enumDef);421  StringRef enumName = enumInfo.getEnumClassName();422  StringRef symToStrFnName = enumInfo.getSymbolToStringFnName();423  StringRef symToStrFnRetType = enumInfo.getSymbolToStringFnRetType();424  auto enumerants = enumInfo.getAllCases();425 426  os << formatv("{2} {1}({0} val) {{\n", enumName, symToStrFnName,427                symToStrFnRetType);428  os << "  switch (val) {\n";429  for (const auto &enumerant : enumerants) {430    auto symbol = enumerant.getSymbol();431    auto str = enumerant.getStr();432    os << formatv("    case {0}::{1}: return \"{2}\";\n", enumName,433                  makeIdentifier(symbol), str);434  }435  os << "  }\n";436  os << "  return \"\";\n";437  os << "}\n\n";438}439 440static void emitSymToStrFnForBitEnum(const Record &enumDef, raw_ostream &os) {441  EnumInfo enumInfo(enumDef);442  StringRef enumName = enumInfo.getEnumClassName();443  StringRef symToStrFnName = enumInfo.getSymbolToStringFnName();444  StringRef symToStrFnRetType = enumInfo.getSymbolToStringFnRetType();445  StringRef separator = enumDef.getValueAsString("separator");446  auto enumerants = enumInfo.getAllCases();447  auto allBitsUnsetCase = getAllBitsUnsetCase(enumerants);448 449  os << formatv("{2} {1}({0} symbol) {{\n", enumName, symToStrFnName,450                symToStrFnRetType);451 452  os << formatv("  auto val = static_cast<{0}>(symbol);\n",453                enumInfo.getUnderlyingType());454  // If we have unknown bit set, return an empty string to signal errors.455  int64_t validBits = enumDef.getValueAsInt("validBits");456  os << formatv("  assert({0}u == ({0}u | val) && \"invalid bits set in bit "457                "enum\");\n",458                validBits);459  if (allBitsUnsetCase) {460    os << "  // Special case for all bits unset.\n";461    os << formatv("  if (val == 0) return \"{0}\";\n\n",462                  allBitsUnsetCase->getStr());463  }464  os << "  ::llvm::SmallVector<::llvm::StringRef, 2> strs;\n";465 466  // Add case string if the value has all case bits, and remove them to avoid467  // printing again. Used only for groups, when printBitEnumPrimaryGroups is 1.468  const char *const formatCompareRemove = R"(469  if ({0}u == ({0}u & val)) {{470    strs.push_back("{1}");471    val &= ~static_cast<{2}>({0});472  }473)";474  // Add case string if the value has all case bits. Used for individual bit475  // cases, and for groups when printBitEnumPrimaryGroups is 0.476  const char *const formatCompare = R"(477  if ({0}u == ({0}u & val))478    strs.push_back("{1}");479)";480  // Optionally elide bits that are members of groups that will also be printed481  // for more concise output.482  if (enumInfo.printBitEnumPrimaryGroups()) {483    os << "  // Print bit enum groups before individual bits\n";484    // Emit comparisons for group bit cases in reverse tablegen declaration485    // order, removing bits for groups with all bits present.486    for (const auto &enumerant : llvm::reverse(enumerants)) {487      if ((enumerant.getValue() != 0) &&488          (enumerant.getDef().isSubClassOf("BitEnumCaseGroup") ||489           enumerant.getDef().isSubClassOf("BitEnumAttrCaseGroup"))) {490        os << formatv(formatCompareRemove, enumerant.getValue(),491                      enumerant.getStr(), enumInfo.getUnderlyingType());492      }493    }494    // Emit comparisons for individual bit cases in tablegen declaration order.495    for (const auto &enumerant : enumerants) {496      if ((enumerant.getValue() != 0) &&497          (enumerant.getDef().isSubClassOf("BitEnumCaseBit") ||498           enumerant.getDef().isSubClassOf("BitEnumAttrCaseBit")))499        os << formatv(formatCompare, enumerant.getValue(), enumerant.getStr());500    }501  } else {502    // Emit comparisons for ALL nonzero cases (individual bits and groups) in503    // tablegen declaration order.504    for (const auto &enumerant : enumerants) {505      if (enumerant.getValue() != 0)506        os << formatv(formatCompare, enumerant.getValue(), enumerant.getStr());507    }508  }509  os << formatv("  return ::llvm::join(strs, \"{0}\");\n", separator);510 511  os << "}\n\n";512}513 514static void emitStrToSymFnForIntEnum(const Record &enumDef, raw_ostream &os) {515  EnumInfo enumInfo(enumDef);516  StringRef enumName = enumInfo.getEnumClassName();517  StringRef strToSymFnName = enumInfo.getStringToSymbolFnName();518  auto enumerants = enumInfo.getAllCases();519 520  os << formatv("::std::optional<{0}> {1}(::llvm::StringRef str) {{\n",521                enumName, strToSymFnName);522  os << formatv("  return ::llvm::StringSwitch<::std::optional<{0}>>(str)\n",523                enumName);524  for (const auto &enumerant : enumerants) {525    auto symbol = enumerant.getSymbol();526    auto str = enumerant.getStr();527    os << formatv("      .Case(\"{1}\", {0}::{2})\n", enumName, str,528                  makeIdentifier(symbol));529  }530  os << "      .Default(::std::nullopt);\n";531  os << "}\n";532}533 534static void emitStrToSymFnForBitEnum(const Record &enumDef, raw_ostream &os) {535  EnumInfo enumInfo(enumDef);536  StringRef enumName = enumInfo.getEnumClassName();537  std::string underlyingType = std::string(enumInfo.getUnderlyingType());538  StringRef strToSymFnName = enumInfo.getStringToSymbolFnName();539  StringRef separator = enumDef.getValueAsString("separator");540  StringRef separatorTrimmed = separator.trim();541  auto enumerants = enumInfo.getAllCases();542  auto allBitsUnsetCase = getAllBitsUnsetCase(enumerants);543 544  os << formatv("::std::optional<{0}> {1}(::llvm::StringRef str) {{\n",545                enumName, strToSymFnName);546 547  if (allBitsUnsetCase) {548    os << "  // Special case for all bits unset.\n";549    StringRef caseSymbol = allBitsUnsetCase->getSymbol();550    os << formatv("  if (str == \"{1}\") return {0}::{2};\n\n", enumName,551                  allBitsUnsetCase->getStr(), makeIdentifier(caseSymbol));552  }553 554  // Split the string to get symbols for all the bits.555  os << "  ::llvm::SmallVector<::llvm::StringRef, 2> symbols;\n";556  // Remove whitespace from the separator string when parsing.557  os << formatv("  str.split(symbols, \"{0}\");\n\n", separatorTrimmed);558 559  os << formatv("  {0} val = 0;\n", underlyingType);560  os << "  for (auto symbol : symbols) {\n";561 562  // Convert each symbol to the bit ordinal and set the corresponding bit.563  os << formatv("    auto bit = "564                "llvm::StringSwitch<::std::optional<{0}>>(symbol.trim())\n",565                underlyingType);566  for (const auto &enumerant : enumerants) {567    // Skip the special enumerant for None.568    if (auto val = enumerant.getValue())569      os.indent(6) << formatv(".Case(\"{0}\", {1})\n", enumerant.getStr(), val);570  }571  os.indent(6) << ".Default(::std::nullopt);\n";572 573  os << "    if (bit) { val |= *bit; } else { return ::std::nullopt; }\n";574  os << "  }\n";575 576  os << formatv("  return static_cast<{0}>(val);\n", enumName);577  os << "}\n\n";578}579 580static void emitUnderlyingToSymFnForIntEnum(const Record &enumDef,581                                            raw_ostream &os) {582  EnumInfo enumInfo(enumDef);583  StringRef enumName = enumInfo.getEnumClassName();584  std::string underlyingType = std::string(enumInfo.getUnderlyingType());585  StringRef underlyingToSymFnName = enumInfo.getUnderlyingToSymbolFnName();586  auto enumerants = enumInfo.getAllCases();587 588  // Avoid generating the underlying value to symbol conversion function if589  // there is an enumerant without explicit value.590  if (llvm::any_of(enumerants,591                   [](EnumCase enumerant) { return enumerant.getValue() < 0; }))592    return;593 594  os << formatv("::std::optional<{0}> {1}({2} value) {{\n", enumName,595                underlyingToSymFnName,596                underlyingType.empty() ? std::string("unsigned")597                                       : underlyingType)598     << "  switch (value) {\n";599  for (const auto &enumerant : enumerants) {600    auto symbol = enumerant.getSymbol();601    auto value = enumerant.getValue();602    os << formatv("  case {0}: return {1}::{2};\n", value, enumName,603                  makeIdentifier(symbol));604  }605  os << "  default: return ::std::nullopt;\n"606     << "  }\n"607     << "}\n\n";608}609 610static void emitSpecializedAttrDef(const Record &enumDef, raw_ostream &os) {611  EnumInfo enumInfo(enumDef);612  StringRef enumName = enumInfo.getEnumClassName();613  StringRef attrClassName = enumInfo.getSpecializedAttrClassName();614  const Record *baseAttrDef = enumInfo.getBaseAttrClass();615  Attribute baseAttr(baseAttrDef);616 617  // Emit classof method618 619  os << formatv("bool {0}::classof(::mlir::Attribute attr) {{\n",620                attrClassName);621 622  mlir::tblgen::Pred baseAttrPred = baseAttr.getPredicate();623  if (baseAttrPred.isNull())624    PrintFatalError("ERROR: baseAttrClass for EnumAttr has no Predicate\n");625 626  std::string condition = baseAttrPred.getCondition();627  FmtContext verifyCtx;628  verifyCtx.withSelf("attr");629  os << tgfmt("  return $0;\n", /*ctx=*/nullptr, tgfmt(condition, &verifyCtx));630 631  os << "}\n";632 633  // Emit get method634 635  os << formatv("{0} {0}::get(::mlir::MLIRContext *context, {1} val) {{\n",636                attrClassName, enumName);637 638  StringRef underlyingType = enumInfo.getUnderlyingType();639 640  // Assuming that it is IntegerAttr constraint641  int64_t bitwidth = 64;642  if (baseAttrDef->getValue("valueType")) {643    auto *valueTypeDef = baseAttrDef->getValueAsDef("valueType");644    if (valueTypeDef->getValue("bitwidth"))645      bitwidth = valueTypeDef->getValueAsInt("bitwidth");646  }647 648  os << formatv("  ::mlir::IntegerType intType = "649                "::mlir::IntegerType::get(context, {0});\n",650                bitwidth);651  os << formatv("  ::mlir::IntegerAttr baseAttr = "652                "::mlir::IntegerAttr::get(intType, static_cast<{0}>(val));\n",653                underlyingType);654  os << formatv("  return ::llvm::cast<{0}>(baseAttr);\n", attrClassName);655 656  os << "}\n";657 658  // Emit getValue method659 660  os << formatv("{0} {1}::getValue() const {{\n", enumName, attrClassName);661 662  os << formatv(663      "  return "664      "static_cast<{0}>(::mlir::IntegerAttr::getValue().getZExtValue());\n",665      enumName);666 667  os << "}\n";668}669 670static void emitUnderlyingToSymFnForBitEnum(const Record &enumDef,671                                            raw_ostream &os) {672  EnumInfo enumInfo(enumDef);673  StringRef enumName = enumInfo.getEnumClassName();674  std::string underlyingType = std::string(enumInfo.getUnderlyingType());675  StringRef underlyingToSymFnName = enumInfo.getUnderlyingToSymbolFnName();676  auto enumerants = enumInfo.getAllCases();677  auto allBitsUnsetCase = getAllBitsUnsetCase(enumerants);678 679  os << formatv("::std::optional<{0}> {1}({2} value) {{\n", enumName,680                underlyingToSymFnName, underlyingType);681  if (allBitsUnsetCase) {682    os << "  // Special case for all bits unset.\n";683    os << formatv("  if (value == 0) return {0}::{1};\n\n", enumName,684                  makeIdentifier(allBitsUnsetCase->getSymbol()));685  }686  int64_t validBits = enumDef.getValueAsInt("validBits");687  os << formatv("  if (value & ~static_cast<{0}>({1}u)) return std::nullopt;\n",688                underlyingType, validBits);689  os << formatv("  return static_cast<{0}>(value);\n", enumName);690  os << "}\n";691}692 693static void emitEnumDecl(const Record &enumDef, raw_ostream &os) {694  EnumInfo enumInfo(enumDef);695  StringRef enumName = enumInfo.getEnumClassName();696  StringRef cppNamespace = enumInfo.getCppNamespace();697  std::string underlyingType = std::string(enumInfo.getUnderlyingType());698  StringRef description = enumInfo.getSummary();699  StringRef strToSymFnName = enumInfo.getStringToSymbolFnName();700  StringRef symToStrFnName = enumInfo.getSymbolToStringFnName();701  StringRef symToStrFnRetType = enumInfo.getSymbolToStringFnRetType();702  StringRef underlyingToSymFnName = enumInfo.getUnderlyingToSymbolFnName();703  auto enumerants = enumInfo.getAllCases();704 705  {706    llvm::NamespaceEmitter ns(os, cppNamespace);707 708    // Emit the enum class definition709    emitEnumClass(enumDef, enumName, underlyingType, description, enumerants,710                  os);711 712    // Emit conversion function declarations713    if (llvm::all_of(enumerants, [](EnumCase enumerant) {714          return enumerant.getValue() >= 0;715        })) {716      os << formatv(717          "::std::optional<{0}> {1}({2});\n", enumName, underlyingToSymFnName,718          underlyingType.empty() ? std::string("unsigned") : underlyingType);719    }720    os << formatv("{2} {1}({0});\n", enumName, symToStrFnName,721                  symToStrFnRetType);722    os << formatv("::std::optional<{0}> {1}(::llvm::StringRef);\n", enumName,723                  strToSymFnName);724 725    if (enumInfo.isBitEnum()) {726      emitOperators(enumDef, os);727    } else {728      emitMaxValueFn(enumDef, os);729    }730 731    // Generate a generic `stringifyEnum` function that forwards to the method732    // specified by the user.733    const char *const stringifyEnumStr = R"(734inline {0} stringifyEnum({1} enumValue) {{735  return {2}(enumValue);736}737)";738    os << formatv(stringifyEnumStr, symToStrFnRetType, enumName,739                  symToStrFnName);740 741    // Generate a generic `symbolizeEnum` function that forwards to the method742    // specified by the user.743    const char *const symbolizeEnumStr = R"(744template <typename EnumType>745::std::optional<EnumType> symbolizeEnum(::llvm::StringRef);746 747template <>748inline ::std::optional<{0}> symbolizeEnum<{0}>(::llvm::StringRef str) {749  return {1}(str);750}751)";752    os << formatv(symbolizeEnumStr, enumName, strToSymFnName);753 754    const char *const attrClassDecl = R"(755class {1} : public ::mlir::{2} {756public:757  using ValueType = {0};758  using ::mlir::{2}::{2};759  static bool classof(::mlir::Attribute attr);760  static {1} get(::mlir::MLIRContext *context, {0} val);761  {0} getValue() const;762};763)";764    if (enumInfo.genSpecializedAttr()) {765      StringRef attrClassName = enumInfo.getSpecializedAttrClassName();766      StringRef baseAttrClassName = "IntegerAttr";767      os << formatv(attrClassDecl, enumName, attrClassName, baseAttrClassName);768    }769  } // close `ns`.770 771  // Generate a generic parser and printer for the enum.772  std::string qualName =773      std::string(formatv("{0}::{1}", cppNamespace, enumName));774  emitParserPrinter(enumInfo, qualName, cppNamespace, os);775 776  // Emit DenseMapInfo for this enum class777  emitDenseMapInfo(qualName, underlyingType, cppNamespace, os);778}779 780static bool emitEnumDecls(const RecordKeeper &records, raw_ostream &os) {781  llvm::emitSourceFileHeader("Enum Utility Declarations", os, records);782 783  for (const Record *def :784       records.getAllDerivedDefinitionsIfDefined("EnumInfo"))785    emitEnumDecl(*def, os);786 787  return false;788}789 790static void emitEnumDef(const Record &enumDef, raw_ostream &os) {791  EnumInfo enumInfo(enumDef);792 793  llvm::NamespaceEmitter ns(os, enumInfo.getCppNamespace());794 795  if (enumInfo.isBitEnum()) {796    emitSymToStrFnForBitEnum(enumDef, os);797    emitStrToSymFnForBitEnum(enumDef, os);798    emitUnderlyingToSymFnForBitEnum(enumDef, os);799  } else {800    emitSymToStrFnForIntEnum(enumDef, os);801    emitStrToSymFnForIntEnum(enumDef, os);802    emitUnderlyingToSymFnForIntEnum(enumDef, os);803  }804 805  if (enumInfo.genSpecializedAttr())806    emitSpecializedAttrDef(enumDef, os);807}808 809static bool emitEnumDefs(const RecordKeeper &records, raw_ostream &os) {810  llvm::emitSourceFileHeader("Enum Utility Definitions", os, records);811 812  for (const Record *def :813       records.getAllDerivedDefinitionsIfDefined("EnumInfo"))814    emitEnumDef(*def, os);815 816  return false;817}818 819// Registers the enum utility generator to mlir-tblgen.820static mlir::GenRegistration821    genEnumDecls("gen-enum-decls", "Generate enum utility declarations",822                 [](const RecordKeeper &records, raw_ostream &os) {823                   return emitEnumDecls(records, os);824                 });825 826// Registers the enum utility generator to mlir-tblgen.827static mlir::GenRegistration828    genEnumDefs("gen-enum-defs", "Generate enum utility definitions",829                [](const RecordKeeper &records, raw_ostream &os) {830                  return emitEnumDefs(records, os);831                });832