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