brintos

brintos / llvm-project-archived public Read only

0
0
Text · 42.9 KiB · dcb21e7 Raw
1254 lines · cpp
1//===- AttributeParser.cpp - MLIR Attribute Parser Implementation ---------===//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// This file implements the parser for the MLIR Types.10//11//===----------------------------------------------------------------------===//12 13#include "Parser.h"14 15#include "mlir/AsmParser/AsmParserState.h"16#include "mlir/IR/AffineMap.h"17#include "mlir/IR/BuiltinAttributes.h"18#include "mlir/IR/BuiltinDialect.h"19#include "mlir/IR/BuiltinTypes.h"20#include "mlir/IR/DialectResourceBlobManager.h"21#include "mlir/IR/IntegerSet.h"22#include <optional>23 24using namespace mlir;25using namespace mlir::detail;26 27/// Parse an arbitrary attribute.28///29///  attribute-value ::= `unit`30///                    | bool-literal31///                    | integer-literal (`:` (index-type | integer-type))?32///                    | float-literal (`:` float-type)?33///                    | string-literal (`:` type)?34///                    | type35///                    | `[` `:` (integer-type | float-type) tensor-literal `]`36///                    | `[` (attribute-value (`,` attribute-value)*)? `]`37///                    | `{` (attribute-entry (`,` attribute-entry)*)? `}`38///                    | symbol-ref-id (`::` symbol-ref-id)*39///                    | `dense` `<` tensor-literal `>` `:`40///                      (tensor-type | vector-type)41///                    | `sparse` `<` attribute-value `,` attribute-value `>`42///                      `:` (tensor-type | vector-type)43///                    | `strided` `<` `[` comma-separated-int-or-question `]`44///                      (`,` `offset` `:` integer-literal)? `>`45///                    | distinct-attribute46///                    | extended-attribute47///48Attribute Parser::parseAttribute(Type type) {49  switch (getToken().getKind()) {50  // Parse an AffineMap or IntegerSet attribute.51  case Token::kw_affine_map: {52    consumeToken(Token::kw_affine_map);53 54    AffineMap map;55    if (parseToken(Token::less, "expected '<' in affine map") ||56        parseAffineMapReference(map) ||57        parseToken(Token::greater, "expected '>' in affine map"))58      return Attribute();59    return AffineMapAttr::get(map);60  }61  case Token::kw_affine_set: {62    consumeToken(Token::kw_affine_set);63 64    IntegerSet set;65    if (parseToken(Token::less, "expected '<' in integer set") ||66        parseIntegerSetReference(set) ||67        parseToken(Token::greater, "expected '>' in integer set"))68      return Attribute();69    return IntegerSetAttr::get(set);70  }71 72  // Parse an array attribute.73  case Token::l_square: {74    consumeToken(Token::l_square);75    SmallVector<Attribute, 4> elements;76    auto parseElt = [&]() -> ParseResult {77      elements.push_back(parseAttribute());78      return elements.back() ? success() : failure();79    };80 81    if (parseCommaSeparatedListUntil(Token::r_square, parseElt))82      return nullptr;83    return builder.getArrayAttr(elements);84  }85 86  // Parse a boolean attribute.87  case Token::kw_false:88    consumeToken(Token::kw_false);89    return builder.getBoolAttr(false);90  case Token::kw_true:91    consumeToken(Token::kw_true);92    return builder.getBoolAttr(true);93 94  // Parse a dense elements attribute.95  case Token::kw_dense:96    return parseDenseElementsAttr(type);97 98  // Parse a dense resource elements attribute.99  case Token::kw_dense_resource:100    return parseDenseResourceElementsAttr(type);101 102  // Parse a dense array attribute.103  case Token::kw_array:104    return parseDenseArrayAttr(type);105 106  // Parse a dictionary attribute.107  case Token::l_brace: {108    NamedAttrList elements;109    if (parseAttributeDict(elements))110      return nullptr;111    return elements.getDictionary(getContext());112  }113 114  // Parse an extended attribute, i.e. alias or dialect attribute.115  case Token::hash_identifier:116    return parseExtendedAttr(type);117 118  // Parse floating point and integer attributes.119  case Token::floatliteral:120    return parseFloatAttr(type, /*isNegative=*/false);121  case Token::integer:122    return parseDecOrHexAttr(type, /*isNegative=*/false);123  case Token::minus: {124    consumeToken(Token::minus);125    if (getToken().is(Token::integer))126      return parseDecOrHexAttr(type, /*isNegative=*/true);127    if (getToken().is(Token::floatliteral))128      return parseFloatAttr(type, /*isNegative=*/true);129 130    return (emitWrongTokenError(131                "expected constant integer or floating point value"),132            nullptr);133  }134 135  // Parse a location attribute.136  case Token::kw_loc: {137    consumeToken(Token::kw_loc);138 139    LocationAttr locAttr;140    if (parseToken(Token::l_paren, "expected '(' in inline location") ||141        parseLocationInstance(locAttr) ||142        parseToken(Token::r_paren, "expected ')' in inline location"))143      return Attribute();144    return locAttr;145  }146 147  // Parse a sparse elements attribute.148  case Token::kw_sparse:149    return parseSparseElementsAttr(type);150 151  // Parse a strided layout attribute.152  case Token::kw_strided:153    return parseStridedLayoutAttr();154 155  // Parse a distinct attribute.156  case Token::kw_distinct:157    return parseDistinctAttr(type);158 159  // Parse a string attribute.160  case Token::string: {161    auto val = getToken().getStringValue();162    consumeToken(Token::string);163    // Parse the optional trailing colon type if one wasn't explicitly provided.164    if (!type && consumeIf(Token::colon) && !(type = parseType()))165      return Attribute();166 167    return type ? StringAttr::get(val, type)168                : StringAttr::get(getContext(), val);169  }170 171  // Parse a symbol reference attribute.172  case Token::at_identifier: {173    // When populating the parser state, this is a list of locations for all of174    // the nested references.175    SmallVector<SMRange> referenceLocations;176    if (state.asmState)177      referenceLocations.push_back(getToken().getLocRange());178 179    // Parse the top-level reference.180    std::string nameStr = getToken().getSymbolReference();181    consumeToken(Token::at_identifier);182 183    // Parse any nested references.184    std::vector<FlatSymbolRefAttr> nestedRefs;185    while (getToken().is(Token::colon)) {186      // Check for the '::' prefix.187      const char *curPointer = getToken().getLoc().getPointer();188      consumeToken(Token::colon);189      if (!consumeIf(Token::colon)) {190        if (getToken().isNot(Token::eof, Token::error)) {191          state.lex.resetPointer(curPointer);192          consumeToken();193        }194        break;195      }196      // Parse the reference itself.197      auto curLoc = getToken().getLoc();198      if (getToken().isNot(Token::at_identifier)) {199        emitError(curLoc, "expected nested symbol reference identifier");200        return Attribute();201      }202 203      // If we are populating the assembly state, add the location for this204      // reference.205      if (state.asmState)206        referenceLocations.push_back(getToken().getLocRange());207 208      std::string nameStr = getToken().getSymbolReference();209      consumeToken(Token::at_identifier);210      nestedRefs.push_back(SymbolRefAttr::get(getContext(), nameStr));211    }212    SymbolRefAttr symbolRefAttr =213        SymbolRefAttr::get(getContext(), nameStr, nestedRefs);214 215    // If we are populating the assembly state, record this symbol reference.216    if (state.asmState)217      state.asmState->addUses(symbolRefAttr, referenceLocations);218    return symbolRefAttr;219  }220 221  // Parse a 'unit' attribute.222  case Token::kw_unit:223    consumeToken(Token::kw_unit);224    return builder.getUnitAttr();225 226    // Handle completion of an attribute.227  case Token::code_complete:228    if (getToken().isCodeCompletionFor(Token::hash_identifier))229      return parseExtendedAttr(type);230    return codeCompleteAttribute();231 232  default:233    // Parse a type attribute. We parse `Optional` here to allow for providing a234    // better error message.235    Type type;236    OptionalParseResult result = parseOptionalType(type);237    if (!result.has_value())238      return emitWrongTokenError("expected attribute value"), Attribute();239    return failed(*result) ? Attribute() : TypeAttr::get(type);240  }241}242 243/// Parse an optional attribute with the provided type.244OptionalParseResult Parser::parseOptionalAttribute(Attribute &attribute,245                                                   Type type) {246  switch (getToken().getKind()) {247  case Token::at_identifier:248  case Token::floatliteral:249  case Token::integer:250  case Token::hash_identifier:251  case Token::kw_affine_map:252  case Token::kw_affine_set:253  case Token::kw_dense:254  case Token::kw_dense_resource:255  case Token::kw_false:256  case Token::kw_loc:257  case Token::kw_sparse:258  case Token::kw_true:259  case Token::kw_unit:260  case Token::l_brace:261  case Token::l_square:262  case Token::minus:263  case Token::string:264    attribute = parseAttribute(type);265    return success(attribute != nullptr);266 267  default:268    // Parse an optional type attribute.269    Type type;270    OptionalParseResult result = parseOptionalType(type);271    if (result.has_value() && succeeded(*result))272      attribute = TypeAttr::get(type);273    return result;274  }275}276OptionalParseResult Parser::parseOptionalAttribute(ArrayAttr &attribute,277                                                   Type type) {278  return parseOptionalAttributeWithToken(Token::l_square, attribute, type);279}280OptionalParseResult Parser::parseOptionalAttribute(StringAttr &attribute,281                                                   Type type) {282  return parseOptionalAttributeWithToken(Token::string, attribute, type);283}284OptionalParseResult Parser::parseOptionalAttribute(SymbolRefAttr &result,285                                                   Type type) {286  return parseOptionalAttributeWithToken(Token::at_identifier, result, type);287}288 289/// Attribute dictionary.290///291///   attribute-dict ::= `{` `}`292///                    | `{` attribute-entry (`,` attribute-entry)* `}`293///   attribute-entry ::= (bare-id | string-literal) `=` attribute-value294///295ParseResult Parser::parseAttributeDict(NamedAttrList &attributes) {296  llvm::SmallDenseSet<StringAttr> seenKeys;297  auto parseElt = [&]() -> ParseResult {298    // The name of an attribute can either be a bare identifier, or a string.299    std::optional<StringAttr> nameId;300    if (getToken().is(Token::string))301      nameId = builder.getStringAttr(getToken().getStringValue());302    else if (getToken().isAny(Token::bare_identifier, Token::inttype) ||303             getToken().isKeyword())304      nameId = builder.getStringAttr(getTokenSpelling());305    else306      return emitWrongTokenError("expected attribute name");307 308    if (nameId->empty())309      return emitError("expected valid attribute name");310 311    if (!seenKeys.insert(*nameId).second)312      return emitError("duplicate key '")313             << nameId->getValue() << "' in dictionary attribute";314    consumeToken();315 316    // Lazy load a dialect in the context if there is a possible namespace.317    auto splitName = nameId->strref().split('.');318    if (!splitName.second.empty())319      getContext()->getOrLoadDialect(splitName.first);320 321    // Try to parse the '=' for the attribute value.322    if (!consumeIf(Token::equal)) {323      // If there is no '=', we treat this as a unit attribute.324      attributes.push_back({*nameId, builder.getUnitAttr()});325      return success();326    }327 328    auto attr = parseAttribute();329    if (!attr)330      return failure();331    attributes.push_back({*nameId, attr});332    return success();333  };334 335  return parseCommaSeparatedList(Delimiter::Braces, parseElt,336                                 " in attribute dictionary");337}338 339/// Parse a float attribute.340Attribute Parser::parseFloatAttr(Type type, bool isNegative) {341  auto val = getToken().getFloatingPointValue();342  if (!val)343    return (emitError("floating point value too large for attribute"), nullptr);344  consumeToken(Token::floatliteral);345  if (!type) {346    // Default to F64 when no type is specified.347    if (!consumeIf(Token::colon))348      type = builder.getF64Type();349    else if (!(type = parseType()))350      return nullptr;351  }352  if (!isa<FloatType>(type))353    return (emitError("floating point value not valid for specified type"),354            nullptr);355  return FloatAttr::get(type, isNegative ? -*val : *val);356}357 358/// Construct an APint from a parsed value, a known attribute type and359/// sign.360static std::optional<APInt> buildAttributeAPInt(Type type, bool isNegative,361                                                StringRef spelling) {362  // Parse the integer value into an APInt that is big enough to hold the value.363  APInt result;364  bool isHex = spelling.size() > 1 && spelling[1] == 'x';365  if (spelling.getAsInteger(isHex ? 0 : 10, result))366    return std::nullopt;367 368  // Extend or truncate the bitwidth to the right size.369  unsigned width = type.isIndex() ? IndexType::kInternalStorageBitWidth370                                  : type.getIntOrFloatBitWidth();371 372  if (width > result.getBitWidth()) {373    result = result.zext(width);374  } else if (width < result.getBitWidth()) {375    // The parser can return an unnecessarily wide result with leading zeros.376    // This isn't a problem, but truncating off bits is bad.377    if (result.countl_zero() < result.getBitWidth() - width)378      return std::nullopt;379 380    result = result.trunc(width);381  }382 383  if (width == 0) {384    // 0 bit integers cannot be negative and manipulation of their sign bit will385    // assert, so short-cut validation here.386    if (isNegative)387      return std::nullopt;388  } else if (isNegative) {389    // The value is negative, we have an overflow if the sign bit is not set390    // in the negated apInt.391    result.negate();392    if (!result.isSignBitSet())393      return std::nullopt;394  } else if ((type.isSignedInteger() || type.isIndex()) &&395             result.isSignBitSet()) {396    // The value is a positive signed integer or index,397    // we have an overflow if the sign bit is set.398    return std::nullopt;399  }400 401  return result;402}403 404/// Parse a decimal or a hexadecimal literal, which can be either an integer405/// or a float attribute.406Attribute Parser::parseDecOrHexAttr(Type type, bool isNegative) {407  Token tok = getToken();408  StringRef spelling = tok.getSpelling();409  SMLoc loc = tok.getLoc();410 411  consumeToken(Token::integer);412  if (!type) {413    // Default to i64 if not type is specified.414    if (!consumeIf(Token::colon))415      type = builder.getIntegerType(64);416    else if (!(type = parseType()))417      return nullptr;418  }419 420  if (auto floatType = dyn_cast<FloatType>(type)) {421    std::optional<APFloat> result;422    if (failed(parseFloatFromIntegerLiteral(result, tok, isNegative,423                                            floatType.getFloatSemantics())))424      return Attribute();425    return FloatAttr::get(floatType, *result);426  }427 428  if (!isa<IntegerType, IndexType>(type))429    return emitError(loc, "integer literal not valid for specified type"),430           nullptr;431 432  if (isNegative && type.isUnsignedInteger()) {433    emitError(loc,434              "negative integer literal not valid for unsigned integer type");435    return nullptr;436  }437 438  std::optional<APInt> apInt = buildAttributeAPInt(type, isNegative, spelling);439  if (!apInt)440    return emitError(loc, "integer constant out of range for attribute"),441           nullptr;442  return builder.getIntegerAttr(type, *apInt);443}444 445//===----------------------------------------------------------------------===//446// TensorLiteralParser447//===----------------------------------------------------------------------===//448 449/// Parse elements values stored within a hex string. On success, the values are450/// stored into 'result'.451static ParseResult parseElementAttrHexValues(Parser &parser, Token tok,452                                             std::string &result) {453  if (std::optional<std::string> value = tok.getHexStringValue()) {454    result = std::move(*value);455    return success();456  }457  return parser.emitError(458      tok.getLoc(), "expected string containing hex digits starting with `0x`");459}460 461namespace {462/// This class implements a parser for TensorLiterals. A tensor literal is463/// either a single element (e.g, 5) or a multi-dimensional list of elements464/// (e.g., [[5, 5]]).465class TensorLiteralParser {466public:467  TensorLiteralParser(Parser &p) : p(p) {}468 469  /// Parse the elements of a tensor literal. If 'allowHex' is true, the parser470  /// may also parse a tensor literal that is store as a hex string.471  ParseResult parse(bool allowHex);472 473  /// Build a dense attribute instance with the parsed elements and the given474  /// shaped type.475  DenseElementsAttr getAttr(SMLoc loc, ShapedType type);476 477  ArrayRef<int64_t> getShape() const { return shape; }478 479private:480  /// Get the parsed elements for an integer attribute.481  ParseResult getIntAttrElements(SMLoc loc, Type eltTy,482                                 std::vector<APInt> &intValues);483 484  /// Get the parsed elements for a float attribute.485  ParseResult getFloatAttrElements(SMLoc loc, FloatType eltTy,486                                   std::vector<APFloat> &floatValues);487 488  /// Build a Dense String attribute for the given type.489  DenseElementsAttr getStringAttr(SMLoc loc, ShapedType type, Type eltTy);490 491  /// Build a Dense attribute with hex data for the given type.492  DenseElementsAttr getHexAttr(SMLoc loc, ShapedType type);493 494  /// Parse a single element, returning failure if it isn't a valid element495  /// literal. For example:496  /// parseElement(1) -> Success, 1497  /// parseElement([1]) -> Failure498  ParseResult parseElement();499 500  /// Parse a list of either lists or elements, returning the dimensions of the501  /// parsed sub-tensors in dims. For example:502  ///   parseList([1, 2, 3]) -> Success, [3]503  ///   parseList([[1, 2], [3, 4]]) -> Success, [2, 2]504  ///   parseList([[1, 2], 3]) -> Failure505  ///   parseList([[1, [2, 3]], [4, [5]]]) -> Failure506  ParseResult parseList(SmallVectorImpl<int64_t> &dims);507 508  /// Parse a literal that was printed as a hex string.509  ParseResult parseHexElements();510 511  Parser &p;512 513  /// The shape inferred from the parsed elements.514  SmallVector<int64_t, 4> shape;515 516  /// Storage used when parsing elements, this is a pair of <is_negated, token>.517  std::vector<std::pair<bool, Token>> storage;518 519  /// Storage used when parsing elements that were stored as hex values.520  std::optional<Token> hexStorage;521};522} // namespace523 524/// Parse the elements of a tensor literal. If 'allowHex' is true, the parser525/// may also parse a tensor literal that is store as a hex string.526ParseResult TensorLiteralParser::parse(bool allowHex) {527  // If hex is allowed, check for a string literal.528  if (allowHex && p.getToken().is(Token::string)) {529    hexStorage = p.getToken();530    p.consumeToken(Token::string);531    return success();532  }533  // Otherwise, parse a list or an individual element.534  if (p.getToken().is(Token::l_square))535    return parseList(shape);536  return parseElement();537}538 539/// Build a dense attribute instance with the parsed elements and the given540/// shaped type.541DenseElementsAttr TensorLiteralParser::getAttr(SMLoc loc, ShapedType type) {542  Type eltType = type.getElementType();543 544  // Check to see if we parse the literal from a hex string.545  if (hexStorage &&546      (eltType.isIntOrIndexOrFloat() || isa<ComplexType>(eltType)))547    return getHexAttr(loc, type);548 549  // Check that the parsed storage size has the same number of elements to the550  // type, or is a known splat.551  if (!shape.empty() && getShape() != type.getShape()) {552    p.emitError(loc) << "inferred shape of elements literal ([" << getShape()553                     << "]) does not match type ([" << type.getShape() << "])";554    return nullptr;555  }556 557  // Handle the case where no elements were parsed.558  if (!hexStorage && storage.empty() && type.getNumElements()) {559    p.emitError(loc) << "parsed zero elements, but type (" << type560                     << ") expected at least 1";561    return nullptr;562  }563 564  // Handle complex types in the specific element type cases below.565  bool isComplex = false;566  if (ComplexType complexTy = dyn_cast<ComplexType>(eltType)) {567    eltType = complexTy.getElementType();568    isComplex = true;569    // Complex types have N*2 elements or complex splat.570    // Empty shape may mean a splat or empty literal, only validate splats.571    bool isSplat = shape.empty() && type.getNumElements() != 0;572    if (isSplat && storage.size() != 2) {573      p.emitError(loc) << "parsed " << storage.size() << " elements, but type ("574                       << complexTy << ") expected 2 elements";575      return nullptr;576    }577    if (!shape.empty() &&578        storage.size() != static_cast<size_t>(type.getNumElements()) * 2) {579      p.emitError(loc) << "parsed " << storage.size() << " elements, but type ("580                       << type << ") expected " << type.getNumElements() * 2581                       << " elements";582      return nullptr;583    }584  }585 586  // Handle integer and index types.587  if (eltType.isIntOrIndex()) {588    std::vector<APInt> intValues;589    if (failed(getIntAttrElements(loc, eltType, intValues)))590      return nullptr;591    if (isComplex) {592      // If this is a complex, treat the parsed values as complex values.593      auto complexData = llvm::ArrayRef(594          reinterpret_cast<std::complex<APInt> *>(intValues.data()),595          intValues.size() / 2);596      return DenseElementsAttr::get(type, complexData);597    }598    return DenseElementsAttr::get(type, intValues);599  }600  // Handle floating point types.601  if (FloatType floatTy = dyn_cast<FloatType>(eltType)) {602    std::vector<APFloat> floatValues;603    if (failed(getFloatAttrElements(loc, floatTy, floatValues)))604      return nullptr;605    if (isComplex) {606      // If this is a complex, treat the parsed values as complex values.607      auto complexData = llvm::ArrayRef(608          reinterpret_cast<std::complex<APFloat> *>(floatValues.data()),609          floatValues.size() / 2);610      return DenseElementsAttr::get(type, complexData);611    }612    return DenseElementsAttr::get(type, floatValues);613  }614 615  // Other types are assumed to be string representations.616  return getStringAttr(loc, type, type.getElementType());617}618 619/// Build a Dense Integer attribute for the given type.620ParseResult621TensorLiteralParser::getIntAttrElements(SMLoc loc, Type eltTy,622                                        std::vector<APInt> &intValues) {623  intValues.reserve(storage.size());624  bool isUintType = eltTy.isUnsignedInteger();625  for (const auto &signAndToken : storage) {626    bool isNegative = signAndToken.first;627    const Token &token = signAndToken.second;628    auto tokenLoc = token.getLoc();629 630    if (isNegative && isUintType) {631      return p.emitError(tokenLoc)632             << "expected unsigned integer elements, but parsed negative value";633    }634 635    // Check to see if floating point values were parsed.636    if (token.is(Token::floatliteral)) {637      return p.emitError(tokenLoc)638             << "expected integer elements, but parsed floating-point";639    }640 641    assert(token.isAny(Token::integer, Token::kw_true, Token::kw_false) &&642           "unexpected token type");643    if (token.isAny(Token::kw_true, Token::kw_false)) {644      if (!eltTy.isInteger(1)) {645        return p.emitError(tokenLoc)646               << "expected i1 type for 'true' or 'false' values";647      }648      APInt apInt(1, token.is(Token::kw_true), /*isSigned=*/false);649      intValues.push_back(apInt);650      continue;651    }652 653    // Create APInt values for each element with the correct bitwidth.654    std::optional<APInt> apInt =655        buildAttributeAPInt(eltTy, isNegative, token.getSpelling());656    if (!apInt)657      return p.emitError(tokenLoc, "integer constant out of range for type");658    intValues.push_back(*apInt);659  }660  return success();661}662 663/// Build a Dense Float attribute for the given type.664ParseResult665TensorLiteralParser::getFloatAttrElements(SMLoc loc, FloatType eltTy,666                                          std::vector<APFloat> &floatValues) {667  floatValues.reserve(storage.size());668  for (const auto &signAndToken : storage) {669    bool isNegative = signAndToken.first;670    const Token &token = signAndToken.second;671    std::optional<APFloat> result;672    if (failed(p.parseFloatFromLiteral(result, token, isNegative,673                                       eltTy.getFloatSemantics())))674      return failure();675    floatValues.push_back(*result);676  }677  return success();678}679 680/// Build a Dense String attribute for the given type.681DenseElementsAttr TensorLiteralParser::getStringAttr(SMLoc loc, ShapedType type,682                                                     Type eltTy) {683  if (hexStorage.has_value()) {684    auto stringValue = hexStorage->getStringValue();685    return DenseStringElementsAttr::get(type, {stringValue});686  }687 688  std::vector<std::string> stringValues;689  std::vector<StringRef> stringRefValues;690  stringValues.reserve(storage.size());691  stringRefValues.reserve(storage.size());692 693  for (auto val : storage) {694    if (!val.second.is(Token::string)) {695      p.emitError(loc) << "expected string token, got "696                       << val.second.getSpelling();697      return nullptr;698    }699    stringValues.push_back(val.second.getStringValue());700    stringRefValues.emplace_back(stringValues.back());701  }702 703  return DenseStringElementsAttr::get(type, stringRefValues);704}705 706/// Build a Dense attribute with hex data for the given type.707DenseElementsAttr TensorLiteralParser::getHexAttr(SMLoc loc, ShapedType type) {708  Type elementType = type.getElementType();709  if (!elementType.isIntOrIndexOrFloat() && !isa<ComplexType>(elementType)) {710    p.emitError(loc)711        << "expected floating-point, integer, or complex element type, got "712        << elementType;713    return nullptr;714  }715 716  std::string data;717  if (parseElementAttrHexValues(p, *hexStorage, data))718    return nullptr;719 720  ArrayRef<char> rawData(data);721  bool detectedSplat = false;722  if (!DenseElementsAttr::isValidRawBuffer(type, rawData, detectedSplat)) {723    p.emitError(loc) << "elements hex data size is invalid for provided type: "724                     << type;725    return nullptr;726  }727 728  if (llvm::endianness::native == llvm::endianness::big) {729    // Convert endianess in big-endian(BE) machines. `rawData` is730    // little-endian(LE) because HEX in raw data of dense element attribute731    // is always LE format. It is converted into BE here to be used in BE732    // machines.733    SmallVector<char, 64> outDataVec(rawData.size());734    MutableArrayRef<char> convRawData(outDataVec);735    DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(736        rawData, convRawData, type);737    return DenseElementsAttr::getFromRawBuffer(type, convRawData);738  }739 740  return DenseElementsAttr::getFromRawBuffer(type, rawData);741}742 743ParseResult TensorLiteralParser::parseElement() {744  switch (p.getToken().getKind()) {745  // Parse a boolean element.746  case Token::kw_true:747  case Token::kw_false:748  case Token::floatliteral:749  case Token::integer:750    storage.emplace_back(/*isNegative=*/false, p.getToken());751    p.consumeToken();752    break;753 754  // Parse a signed integer or a negative floating-point element.755  case Token::minus:756    p.consumeToken(Token::minus);757    if (!p.getToken().isAny(Token::floatliteral, Token::integer))758      return p.emitError("expected integer or floating point literal");759    storage.emplace_back(/*isNegative=*/true, p.getToken());760    p.consumeToken();761    break;762 763  case Token::string:764    storage.emplace_back(/*isNegative=*/false, p.getToken());765    p.consumeToken();766    break;767 768  // Parse a complex element of the form '(' element ',' element ')'.769  case Token::l_paren:770    p.consumeToken(Token::l_paren);771    if (parseElement() ||772        p.parseToken(Token::comma, "expected ',' between complex elements") ||773        parseElement() ||774        p.parseToken(Token::r_paren, "expected ')' after complex elements"))775      return failure();776    break;777 778  default:779    return p.emitError("expected element literal of primitive type");780  }781 782  return success();783}784 785/// Parse a list of either lists or elements, returning the dimensions of the786/// parsed sub-tensors in dims. For example:787///   parseList([1, 2, 3]) -> Success, [3]788///   parseList([[1, 2], [3, 4]]) -> Success, [2, 2]789///   parseList([[1, 2], 3]) -> Failure790///   parseList([[1, [2, 3]], [4, [5]]]) -> Failure791ParseResult TensorLiteralParser::parseList(SmallVectorImpl<int64_t> &dims) {792  auto checkDims = [&](const SmallVectorImpl<int64_t> &prevDims,793                       const SmallVectorImpl<int64_t> &newDims) -> ParseResult {794    if (prevDims == newDims)795      return success();796    return p.emitError("tensor literal is invalid; ranks are not consistent "797                       "between elements");798  };799 800  bool first = true;801  SmallVector<int64_t, 4> newDims;802  unsigned size = 0;803  auto parseOneElement = [&]() -> ParseResult {804    SmallVector<int64_t, 4> thisDims;805    if (p.getToken().getKind() == Token::l_square) {806      if (parseList(thisDims))807        return failure();808    } else if (parseElement()) {809      return failure();810    }811    ++size;812    if (!first)813      return checkDims(newDims, thisDims);814    newDims = thisDims;815    first = false;816    return success();817  };818  if (p.parseCommaSeparatedList(Parser::Delimiter::Square, parseOneElement))819    return failure();820 821  // Return the sublists' dimensions with 'size' prepended.822  dims.clear();823  dims.push_back(size);824  dims.append(newDims.begin(), newDims.end());825  return success();826}827 828//===----------------------------------------------------------------------===//829// DenseArrayAttr Parser830//===----------------------------------------------------------------------===//831 832namespace {833/// A generic dense array element parser. It parsers integer and floating point834/// elements.835class DenseArrayElementParser {836public:837  explicit DenseArrayElementParser(Type type) : type(type) {}838 839  /// Parse an integer element.840  ParseResult parseIntegerElement(Parser &p);841 842  /// Parse a floating point element.843  ParseResult parseFloatElement(Parser &p);844 845  /// Convert the current contents to a dense array.846  DenseArrayAttr getAttr() { return DenseArrayAttr::get(type, size, rawData); }847 848private:849  /// Append the raw data of an APInt to the result.850  void append(const APInt &data);851 852  /// The array element type.853  Type type;854  /// The resultant byte array representing the contents of the array.855  std::vector<char> rawData;856  /// The number of elements in the array.857  int64_t size = 0;858};859} // namespace860 861void DenseArrayElementParser::append(const APInt &data) {862  if (data.getBitWidth()) {863    assert(data.getBitWidth() % 8 == 0);864    unsigned byteSize = data.getBitWidth() / 8;865    size_t offset = rawData.size();866    rawData.insert(rawData.end(), byteSize, 0);867    llvm::StoreIntToMemory(868        data, reinterpret_cast<uint8_t *>(rawData.data() + offset), byteSize);869  }870  ++size;871}872 873ParseResult DenseArrayElementParser::parseIntegerElement(Parser &p) {874  bool isNegative = p.consumeIf(Token::minus);875 876  // Parse an integer literal as an APInt.877  std::optional<APInt> value;878  StringRef spelling = p.getToken().getSpelling();879  if (p.getToken().isAny(Token::kw_true, Token::kw_false)) {880    if (!type.isInteger(1))881      return p.emitError("expected i1 type for 'true' or 'false' values");882    value = APInt(/*numBits=*/8, p.getToken().is(Token::kw_true),883                  !type.isUnsignedInteger());884    p.consumeToken();885  } else if (p.consumeIf(Token::integer)) {886    value = buildAttributeAPInt(type, isNegative, spelling);887    if (!value)888      return p.emitError("integer constant out of range");889  } else {890    return p.emitError("expected integer literal");891  }892  append(*value);893  return success();894}895 896ParseResult DenseArrayElementParser::parseFloatElement(Parser &p) {897  bool isNegative = p.consumeIf(Token::minus);898  Token token = p.getToken();899  std::optional<APFloat> fromIntLit;900  if (failed(901          p.parseFloatFromLiteral(fromIntLit, token, isNegative,902                                  cast<FloatType>(type).getFloatSemantics())))903    return failure();904  p.consumeToken();905  append(fromIntLit->bitcastToAPInt());906  return success();907}908 909/// Parse a dense array attribute.910Attribute Parser::parseDenseArrayAttr(Type attrType) {911  consumeToken(Token::kw_array);912  if (parseToken(Token::less, "expected '<' after 'array'"))913    return {};914 915  SMLoc typeLoc = getToken().getLoc();916  Type eltType = parseType();917  if (!eltType) {918    emitError(typeLoc, "expected an integer or floating point type");919    return {};920  }921 922  // Only bool or integer and floating point elements divisible by bytes are923  // supported.924  if (!eltType.isIntOrIndexOrFloat()) {925    emitError(typeLoc, "expected integer or float type, got: ") << eltType;926    return {};927  }928  if (!eltType.isInteger(1) && eltType.getIntOrFloatBitWidth() % 8 != 0) {929    emitError(typeLoc, "element type bitwidth must be a multiple of 8");930    return {};931  }932 933  // Check for empty list.934  if (consumeIf(Token::greater))935    return DenseArrayAttr::get(eltType, 0, {});936 937  if (parseToken(Token::colon, "expected ':' after dense array type"))938    return {};939 940  DenseArrayElementParser eltParser(eltType);941  if (eltType.isIntOrIndex()) {942    if (parseCommaSeparatedList(943            [&] { return eltParser.parseIntegerElement(*this); }))944      return {};945  } else {946    if (parseCommaSeparatedList(947            [&] { return eltParser.parseFloatElement(*this); }))948      return {};949  }950  if (parseToken(Token::greater, "expected '>' to close an array attribute"))951    return {};952  return eltParser.getAttr();953}954 955/// Parse a dense elements attribute.956Attribute Parser::parseDenseElementsAttr(Type attrType) {957  auto attribLoc = getToken().getLoc();958  consumeToken(Token::kw_dense);959  if (parseToken(Token::less, "expected '<' after 'dense'"))960    return nullptr;961 962  // Parse the literal data if necessary.963  TensorLiteralParser literalParser(*this);964  if (!consumeIf(Token::greater)) {965    if (literalParser.parse(/*allowHex=*/true) ||966        parseToken(Token::greater, "expected '>'"))967      return nullptr;968  }969 970  auto type = parseElementsLiteralType(attribLoc, attrType);971  if (!type)972    return nullptr;973  return literalParser.getAttr(attribLoc, type);974}975 976Attribute Parser::parseDenseResourceElementsAttr(Type attrType) {977  auto loc = getToken().getLoc();978  consumeToken(Token::kw_dense_resource);979  if (parseToken(Token::less, "expected '<' after 'dense_resource'"))980    return nullptr;981 982  // Parse the resource handle.983  FailureOr<AsmDialectResourceHandle> rawHandle =984      parseResourceHandle(getContext()->getLoadedDialect<BuiltinDialect>());985  if (failed(rawHandle) || parseToken(Token::greater, "expected '>'"))986    return nullptr;987 988  auto *handle = dyn_cast<DenseResourceElementsHandle>(&*rawHandle);989  if (!handle)990    return emitError(loc, "invalid `dense_resource` handle type"), nullptr;991 992  // Parse the type of the attribute if the user didn't provide one.993  SMLoc typeLoc = loc;994  if (!attrType) {995    typeLoc = getToken().getLoc();996    if (parseToken(Token::colon, "expected ':'") || !(attrType = parseType()))997      return nullptr;998  }999 1000  ShapedType shapedType = dyn_cast<ShapedType>(attrType);1001  if (!shapedType) {1002    emitError(typeLoc, "`dense_resource` expected a shaped type");1003    return nullptr;1004  }1005 1006  return DenseResourceElementsAttr::get(shapedType, *handle);1007}1008 1009/// Shaped type for elements attribute.1010///1011///   elements-literal-type ::= vector-type | ranked-tensor-type1012///1013/// This method also checks the type has static shape.1014ShapedType Parser::parseElementsLiteralType(SMLoc loc, Type type) {1015  // If the user didn't provide a type, parse the colon type for the literal.1016  if (!type) {1017    if (parseToken(Token::colon, "expected ':'"))1018      return nullptr;1019    if (!(type = parseType()))1020      return nullptr;1021  }1022 1023  auto sType = dyn_cast<ShapedType>(type);1024  if (!sType) {1025    emitError(loc, "elements literal must be a shaped type");1026    return nullptr;1027  }1028 1029  if (!sType.hasStaticShape()) {1030    emitError(loc, "elements literal type must have static shape");1031    return nullptr;1032  }1033 1034  return sType;1035}1036 1037/// Parse a sparse elements attribute.1038Attribute Parser::parseSparseElementsAttr(Type attrType) {1039  SMLoc loc = getToken().getLoc();1040  consumeToken(Token::kw_sparse);1041  if (parseToken(Token::less, "Expected '<' after 'sparse'"))1042    return nullptr;1043 1044  // Check for the case where all elements are sparse. The indices are1045  // represented by a 2-dimensional shape where the second dimension is the rank1046  // of the type.1047  Type indiceEltType = builder.getIntegerType(64);1048  if (consumeIf(Token::greater)) {1049    ShapedType type = parseElementsLiteralType(loc, attrType);1050    if (!type)1051      return nullptr;1052 1053    // Construct the sparse elements attr using zero element indice/value1054    // attributes.1055    ShapedType indicesType =1056        RankedTensorType::get({0, type.getRank()}, indiceEltType);1057    ShapedType valuesType = RankedTensorType::get({0}, type.getElementType());1058    return getChecked<SparseElementsAttr>(1059        loc, type, DenseElementsAttr::get(indicesType, ArrayRef<Attribute>()),1060        DenseElementsAttr::get(valuesType, ArrayRef<Attribute>()));1061  }1062 1063  /// Parse the indices. We don't allow hex values here as we may need to use1064  /// the inferred shape.1065  auto indicesLoc = getToken().getLoc();1066  TensorLiteralParser indiceParser(*this);1067  if (indiceParser.parse(/*allowHex=*/false))1068    return nullptr;1069 1070  if (parseToken(Token::comma, "expected ','"))1071    return nullptr;1072 1073  /// Parse the values.1074  auto valuesLoc = getToken().getLoc();1075  TensorLiteralParser valuesParser(*this);1076  if (valuesParser.parse(/*allowHex=*/true))1077    return nullptr;1078 1079  if (parseToken(Token::greater, "expected '>'"))1080    return nullptr;1081 1082  auto type = parseElementsLiteralType(loc, attrType);1083  if (!type)1084    return nullptr;1085 1086  // If the indices are a splat, i.e. the literal parser parsed an element and1087  // not a list, we set the shape explicitly. The indices are represented by a1088  // 2-dimensional shape where the second dimension is the rank of the type.1089  // Given that the parsed indices is a splat, we know that we only have one1090  // indice and thus one for the first dimension.1091  ShapedType indicesType;1092  if (indiceParser.getShape().empty()) {1093    indicesType = RankedTensorType::get({1, type.getRank()}, indiceEltType);1094  } else {1095    // Otherwise, set the shape to the one parsed by the literal parser.1096    indicesType = RankedTensorType::get(indiceParser.getShape(), indiceEltType);1097  }1098  auto indices = indiceParser.getAttr(indicesLoc, indicesType);1099  if (!indices)1100    return nullptr;1101 1102  // If the values are a splat, set the shape explicitly based on the number of1103  // indices. The number of indices is encoded in the first dimension of the1104  // indice shape type.1105  auto valuesEltType = type.getElementType();1106  ShapedType valuesType =1107      valuesParser.getShape().empty()1108          ? RankedTensorType::get({indicesType.getDimSize(0)}, valuesEltType)1109          : RankedTensorType::get(valuesParser.getShape(), valuesEltType);1110  auto values = valuesParser.getAttr(valuesLoc, valuesType);1111  if (!values)1112    return nullptr;1113 1114  // Build the sparse elements attribute by the indices and values.1115  return getChecked<SparseElementsAttr>(loc, type, indices, values);1116}1117 1118Attribute Parser::parseStridedLayoutAttr() {1119  // Callback for error emissing at the keyword token location.1120  llvm::SMLoc loc = getToken().getLoc();1121  auto errorEmitter = [&] { return emitError(loc); };1122 1123  consumeToken(Token::kw_strided);1124  if (failed(parseToken(Token::less, "expected '<' after 'strided'")) ||1125      failed(parseToken(Token::l_square, "expected '['")))1126    return nullptr;1127 1128  // Parses either an integer token or a question mark token. Reports an error1129  // and returns std::nullopt if the current token is neither. The integer token1130  // must fit into int64_t limits.1131  auto parseStrideOrOffset = [&]() -> std::optional<int64_t> {1132    if (consumeIf(Token::question))1133      return ShapedType::kDynamic;1134 1135    SMLoc loc = getToken().getLoc();1136    auto emitWrongTokenError = [&] {1137      emitError(loc, "expected a 64-bit signed integer or '?'");1138      return std::nullopt;1139    };1140 1141    bool negative = consumeIf(Token::minus);1142 1143    if (getToken().is(Token::integer)) {1144      std::optional<uint64_t> value = getToken().getUInt64IntegerValue();1145      if (!value ||1146          *value > static_cast<uint64_t>(std::numeric_limits<int64_t>::max()))1147        return emitWrongTokenError();1148      consumeToken();1149      auto result = static_cast<int64_t>(*value);1150      if (negative)1151        result = -result;1152 1153      return result;1154    }1155 1156    return emitWrongTokenError();1157  };1158 1159  // Parse strides.1160  SmallVector<int64_t> strides;1161  if (!getToken().is(Token::r_square)) {1162    do {1163      std::optional<int64_t> stride = parseStrideOrOffset();1164      if (!stride)1165        return nullptr;1166      strides.push_back(*stride);1167    } while (consumeIf(Token::comma));1168  }1169 1170  if (failed(parseToken(Token::r_square, "expected ']'")))1171    return nullptr;1172 1173  // Fast path in absence of offset.1174  if (consumeIf(Token::greater)) {1175    if (failed(StridedLayoutAttr::verify(errorEmitter,1176                                         /*offset=*/0, strides)))1177      return nullptr;1178    return StridedLayoutAttr::get(getContext(), /*offset=*/0, strides);1179  }1180 1181  if (failed(parseToken(Token::comma, "expected ','")) ||1182      failed(parseToken(Token::kw_offset, "expected 'offset' after comma")) ||1183      failed(parseToken(Token::colon, "expected ':' after 'offset'")))1184    return nullptr;1185 1186  std::optional<int64_t> offset = parseStrideOrOffset();1187  if (!offset || failed(parseToken(Token::greater, "expected '>'")))1188    return nullptr;1189 1190  if (failed(StridedLayoutAttr::verify(errorEmitter, *offset, strides)))1191    return nullptr;1192  return StridedLayoutAttr::get(getContext(), *offset, strides);1193  // return getChecked<StridedLayoutAttr>(loc,getContext(), *offset, strides);1194}1195 1196/// Parse a distinct attribute.1197///1198///  distinct-attribute ::= `distinct`1199///                         `[` integer-literal `]<` attribute-value `>`1200///1201Attribute Parser::parseDistinctAttr(Type type) {1202  SMLoc loc = getToken().getLoc();1203  consumeToken(Token::kw_distinct);1204  if (parseToken(Token::l_square, "expected '[' after 'distinct'"))1205    return {};1206 1207  // Parse the distinct integer identifier.1208  Token token = getToken();1209  if (parseToken(Token::integer, "expected distinct ID"))1210    return {};1211  std::optional<uint64_t> value = token.getUInt64IntegerValue();1212  if (!value) {1213    emitError("expected an unsigned 64-bit integer");1214    return {};1215  }1216 1217  // Parse the referenced attribute.1218  if (parseToken(Token::r_square, "expected ']' to close distinct ID") ||1219      parseToken(Token::less, "expected '<' after distinct ID"))1220    return {};1221 1222  Attribute referencedAttr;1223  if (getToken().is(Token::greater)) {1224    consumeToken();1225    referencedAttr = builder.getUnitAttr();1226  } else {1227    referencedAttr = parseAttribute(type);1228    if (!referencedAttr) {1229      emitError("expected attribute");1230      return {};1231    }1232 1233    if (parseToken(Token::greater, "expected '>' to close distinct attribute"))1234      return {};1235  }1236 1237  // Add the distinct attribute to the parser state, if it has not been parsed1238  // before. Otherwise, check if the parsed reference attribute matches the one1239  // found in the parser state.1240  DenseMap<uint64_t, DistinctAttr> &distinctAttrs =1241      state.symbols.distinctAttributes;1242  auto it = distinctAttrs.find(*value);1243  if (it == distinctAttrs.end()) {1244    DistinctAttr distinctAttr = DistinctAttr::create(referencedAttr);1245    it = distinctAttrs.try_emplace(*value, distinctAttr).first;1246  } else if (it->getSecond().getReferencedAttr() != referencedAttr) {1247    emitError(loc, "referenced attribute does not match previous definition: ")1248        << it->getSecond().getReferencedAttr();1249    return {};1250  }1251 1252  return it->getSecond();1253}1254