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