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