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