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