24 #include "llvm/ADT/StringExtras.h"
25 #include "llvm/Support/Endian.h"
54 case Token::kw_affine_map: {
58 if (
parseToken(Token::less,
"expected '<' in affine map") ||
60 parseToken(Token::greater,
"expected '>' in affine map"))
64 case Token::kw_affine_set: {
68 if (
parseToken(Token::less,
"expected '<' in integer set") ||
70 parseToken(Token::greater,
"expected '>' in integer set"))
76 case Token::l_square: {
102 case Token::kw_dense_resource:
106 case Token::kw_array:
110 case Token::l_brace: {
118 case Token::hash_identifier:
122 case Token::floatliteral:
130 if (
getToken().is(Token::floatliteral))
134 "expected constant integer or floating point value"),
139 case Token::kw_loc: {
143 if (
parseToken(Token::l_paren,
"expected '(' in inline location") ||
145 parseToken(Token::r_paren,
"expected ')' in inline location"))
151 case Token::kw_sparse:
155 case Token::kw_strided:
159 case Token::string: {
171 case Token::at_identifier: {
176 referenceLocations.push_back(
getToken().getLocRange());
183 std::vector<FlatSymbolRefAttr> nestedRefs;
184 while (
getToken().is(Token::colon)) {
189 if (
getToken().isNot(Token::eof, Token::error)) {
197 if (
getToken().isNot(Token::at_identifier)) {
198 emitError(curLoc,
"expected nested symbol reference identifier");
205 referenceLocations.push_back(
getToken().getLocRange());
211 SymbolRefAttr symbolRefAttr =
217 return symbolRefAttr;
226 case Token::code_complete:
227 if (
getToken().isCodeCompletionFor(Token::hash_identifier))
246 case Token::at_identifier:
247 case Token::floatliteral:
249 case Token::hash_identifier:
250 case Token::kw_affine_map:
251 case Token::kw_affine_set:
252 case Token::kw_dense:
253 case Token::kw_dense_resource:
254 case Token::kw_false:
256 case Token::kw_sparse:
260 case Token::l_square:
264 return success(attribute !=
nullptr);
295 llvm::SmallDenseSet<StringAttr> seenKeys;
298 std::optional<StringAttr> nameId;
301 else if (
getToken().
isAny(Token::bare_identifier, Token::inttype) ||
307 if (nameId->size() == 0)
308 return emitError(
"expected valid attribute name");
310 if (!seenKeys.insert(*nameId).second)
312 << nameId->getValue() <<
"' in dictionary attribute";
316 auto splitName = nameId->strref().split(
'.');
317 if (!splitName.second.empty())
335 " in attribute dictionary");
342 return (
emitError(
"floating point value too large for attribute"),
nullptr);
351 if (!isa<FloatType>(type))
352 return (
emitError(
"floating point value not valid for specified type"),
360 StringRef spelling) {
363 bool isHex = spelling.size() > 1 && spelling[1] ==
'x';
364 if (spelling.getAsInteger(isHex ? 0 : 10, result))
368 unsigned width = type.
isIndex() ? IndexType::kInternalStorageBitWidth
371 if (width > result.getBitWidth()) {
372 result = result.zext(width);
373 }
else if (width < result.getBitWidth()) {
376 if (result.countl_zero() < result.getBitWidth() - width)
379 result = result.trunc(width);
387 }
else if (isNegative) {
391 if (!result.isSignBitSet())
394 result.isSignBitSet()) {
419 if (
auto floatType = dyn_cast<FloatType>(type)) {
420 std::optional<APFloat> result;
422 floatType.getFloatSemantics(),
423 floatType.getWidth())))
428 if (!isa<IntegerType, IndexType>(type))
429 return emitError(loc,
"integer literal not valid for specified type"),
434 "negative integer literal not valid for unsigned integer type");
440 return emitError(loc,
"integer constant out of range for attribute"),
452 std::string &result) {
454 result = std::move(*value);
458 tok.
getLoc(),
"expected string containing hex digits starting with `0x`");
465 class TensorLiteralParser {
467 TensorLiteralParser(
Parser &p) : p(p) {}
482 std::vector<APInt> &intValues);
486 std::vector<APFloat> &floatValues);
517 std::vector<std::pair<bool, Token>> storage;
520 std::optional<Token> hexStorage;
526 ParseResult TensorLiteralParser::parse(
bool allowHex) {
528 if (allowHex && p.getToken().is(Token::string)) {
529 hexStorage = p.getToken();
530 p.consumeToken(Token::string);
534 if (p.getToken().is(Token::l_square))
535 return parseList(shape);
536 return parseElement();
542 Type eltType = type.getElementType();
547 return getHexAttr(loc, type);
551 if (!shape.empty() &&
getShape() != type.getShape()) {
552 p.emitError(loc) <<
"inferred shape of elements literal ([" <<
getShape()
553 <<
"]) does not match type ([" << type.getShape() <<
"])";
558 if (!hexStorage && storage.empty() && type.getNumElements()) {
559 p.emitError(loc) <<
"parsed zero elements, but type (" << type
560 <<
") expected at least 1";
565 bool isComplex =
false;
566 if (ComplexType complexTy = dyn_cast<ComplexType>(eltType)) {
567 eltType = complexTy.getElementType();
573 std::vector<APInt> intValues;
574 if (
failed(getIntAttrElements(loc, eltType, intValues)))
579 reinterpret_cast<std::complex<APInt> *
>(intValues.data()),
580 intValues.size() / 2);
586 if (
FloatType floatTy = dyn_cast<FloatType>(eltType)) {
587 std::vector<APFloat> floatValues;
588 if (
failed(getFloatAttrElements(loc, floatTy, floatValues)))
593 reinterpret_cast<std::complex<APFloat> *
>(floatValues.data()),
594 floatValues.size() / 2);
601 return getStringAttr(loc, type, type.getElementType());
606 TensorLiteralParser::getIntAttrElements(SMLoc loc,
Type eltTy,
607 std::vector<APInt> &intValues) {
608 intValues.reserve(storage.size());
610 for (
const auto &signAndToken : storage) {
611 bool isNegative = signAndToken.first;
612 const Token &token = signAndToken.second;
613 auto tokenLoc = token.
getLoc();
615 if (isNegative && isUintType) {
616 return p.emitError(tokenLoc)
617 <<
"expected unsigned integer elements, but parsed negative value";
621 if (token.
is(Token::floatliteral)) {
622 return p.emitError(tokenLoc)
623 <<
"expected integer elements, but parsed floating-point";
626 assert(token.
isAny(Token::integer, Token::kw_true, Token::kw_false) &&
627 "unexpected token type");
628 if (token.
isAny(Token::kw_true, Token::kw_false)) {
630 return p.emitError(tokenLoc)
631 <<
"expected i1 type for 'true' or 'false' values";
633 APInt apInt(1, token.
is(Token::kw_true),
false);
634 intValues.push_back(apInt);
639 std::optional<APInt> apInt =
642 return p.emitError(tokenLoc,
"integer constant out of range for type");
643 intValues.push_back(*apInt);
650 TensorLiteralParser::getFloatAttrElements(SMLoc loc,
FloatType eltTy,
651 std::vector<APFloat> &floatValues) {
652 floatValues.reserve(storage.size());
653 for (
const auto &signAndToken : storage) {
654 bool isNegative = signAndToken.first;
655 const Token &token = signAndToken.second;
658 if (token.
is(Token::integer) && token.
getSpelling().startswith(
"0x")) {
659 std::optional<APFloat> result;
660 if (
failed(p.parseFloatFromIntegerLiteral(result, token, isNegative,
665 floatValues.push_back(*result);
670 if (!token.
is(Token::floatliteral))
672 <<
"expected floating-point elements, but parsed integer";
677 return p.emitError(
"floating point value too large for attribute");
679 APFloat apVal(isNegative ? -*val : *val);
680 if (!eltTy.
isF64()) {
685 floatValues.push_back(apVal);
693 if (hexStorage.has_value()) {
694 auto stringValue = hexStorage->getStringValue();
698 std::vector<std::string> stringValues;
699 std::vector<StringRef> stringRefValues;
700 stringValues.reserve(storage.size());
701 stringRefValues.reserve(storage.size());
703 for (
auto val : storage) {
704 stringValues.push_back(val.second.getStringValue());
705 stringRefValues.emplace_back(stringValues.back());
713 Type elementType = type.getElementType();
716 <<
"expected floating-point, integer, or complex element type, got "
726 bool detectedSplat =
false;
728 p.emitError(loc) <<
"elements hex data size is invalid for provided type: "
733 if (llvm::support::endian::system_endianness() ==
734 llvm::support::endianness::big) {
741 DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
742 rawData, convRawData, type);
750 switch (p.getToken().getKind()) {
753 case Token::kw_false:
754 case Token::floatliteral:
756 storage.emplace_back(
false, p.getToken());
762 p.consumeToken(Token::minus);
763 if (!p.getToken().isAny(Token::floatliteral, Token::integer))
764 return p.emitError(
"expected integer or floating point literal");
765 storage.emplace_back(
true, p.getToken());
770 storage.emplace_back(
false, p.getToken());
776 p.consumeToken(Token::l_paren);
777 if (parseElement() ||
778 p.parseToken(Token::comma,
"expected ',' between complex elements") ||
780 p.parseToken(Token::r_paren,
"expected ')' after complex elements"))
785 return p.emitError(
"expected element literal of primitive type");
800 if (prevDims == newDims)
802 return p.emitError(
"tensor literal is invalid; ranks are not consistent "
811 if (p.getToken().getKind() == Token::l_square) {
812 if (parseList(thisDims))
814 }
else if (parseElement()) {
819 return checkDims(newDims, thisDims);
829 dims.push_back(size);
830 dims.append(newDims.begin(), newDims.end());
841 class DenseArrayElementParser {
843 explicit DenseArrayElementParser(
Type type) : type(type) {}
856 void append(
const APInt &data);
861 std::vector<char> rawData;
867 void DenseArrayElementParser::append(
const APInt &data) {
868 if (data.getBitWidth()) {
869 assert(data.getBitWidth() % 8 == 0);
870 unsigned byteSize = data.getBitWidth() / 8;
871 size_t offset = rawData.size();
872 rawData.insert(rawData.end(), byteSize, 0);
873 llvm::StoreIntToMemory(
874 data,
reinterpret_cast<uint8_t *
>(rawData.data() + offset), byteSize);
880 bool isNegative = p.
consumeIf(Token::minus);
883 std::optional<APInt> value;
886 if (!type.isInteger(1))
887 return p.
emitError(
"expected i1 type for 'true' or 'false' values");
888 value = APInt(8, p.
getToken().
is(Token::kw_true),
889 !type.isUnsignedInteger());
891 }
else if (p.
consumeIf(Token::integer)) {
894 return p.
emitError(
"integer constant out of range");
896 return p.
emitError(
"expected integer literal");
903 bool isNegative = p.
consumeIf(Token::minus);
906 std::optional<APFloat> result;
907 auto floatType = cast<FloatType>(type);
911 floatType.getFloatSemantics(),
912 floatType.getWidth()))
914 }
else if (p.
consumeIf(Token::floatliteral)) {
919 result = APFloat(isNegative ? -*val : *val);
922 result->convert(floatType.getFloatSemantics(),
923 APFloat::rmNearestTiesToEven, &unused);
926 return p.
emitError(
"expected integer or floating point literal");
929 append(result->bitcastToAPInt());
936 if (
parseToken(Token::less,
"expected '<' after 'array'"))
942 emitError(typeLoc,
"expected an integer or floating point type");
949 emitError(typeLoc,
"expected integer or float type, got: ") << eltType;
953 emitError(typeLoc,
"element type bitwidth must be a multiple of 8");
961 if (
parseToken(Token::colon,
"expected ':' after dense array type"))
964 DenseArrayElementParser eltParser(eltType);
967 [&] {
return eltParser.parseIntegerElement(*
this); }))
971 [&] {
return eltParser.parseFloatElement(*
this); }))
974 if (
parseToken(Token::greater,
"expected '>' to close an array attribute"))
976 return eltParser.getAttr();
983 if (
parseToken(Token::less,
"expected '<' after 'dense'"))
987 TensorLiteralParser literalParser(*
this);
989 if (literalParser.parse(
true) ||
1001 return literalParser.getAttr(loc, type);
1007 if (
parseToken(Token::less,
"expected '<' after 'dense_resource'"))
1016 auto *handle = dyn_cast<DenseResourceElementsHandle>(&*rawHandle);
1018 return emitError(loc,
"invalid `dense_resource` handle type"),
nullptr;
1021 SMLoc typeLoc = loc;
1028 ShapedType shapedType = dyn_cast<ShapedType>(attrType);
1030 emitError(typeLoc,
"`dense_resource` expected a shaped type");
1045 if (
parseToken(Token::colon,
"expected ':'"))
1051 auto sType = dyn_cast<ShapedType>(type);
1053 emitError(
"elements literal must be a shaped type");
1057 if (!sType.hasStaticShape())
1058 return (
emitError(
"elements literal type must have static shape"),
nullptr);
1067 if (
parseToken(Token::less,
"Expected '<' after 'sparse'"))
1081 ShapedType indicesType =
1084 return getChecked<SparseElementsAttr>(
1092 TensorLiteralParser indiceParser(*
this);
1093 if (indiceParser.parse(
false))
1096 if (
parseToken(Token::comma,
"expected ','"))
1101 TensorLiteralParser valuesParser(*
this);
1102 if (valuesParser.parse(
true))
1105 if (
parseToken(Token::greater,
"expected '>'"))
1117 ShapedType indicesType;
1118 if (indiceParser.getShape().empty()) {
1124 auto indices = indiceParser.getAttr(indicesLoc, indicesType);
1129 auto valuesEltType = type.getElementType();
1130 ShapedType valuesType =
1131 valuesParser.getShape().empty()
1134 auto values = valuesParser.getAttr(valuesLoc, valuesType);
1137 return getChecked<SparseElementsAttr>(loc, type, indices, values);
1143 auto errorEmitter = [&] {
return emitError(loc); };
1153 auto parseStrideOrOffset = [&]() -> std::optional<int64_t> {
1155 return ShapedType::kDynamic;
1159 emitError(loc,
"expected a 64-bit signed integer or '?'");
1160 return std::nullopt;
1163 bool negative =
consumeIf(Token::minus);
1165 if (
getToken().is(Token::integer)) {
1171 auto result =
static_cast<int64_t
>(*value);
1183 if (!
getToken().is(Token::r_square)) {
1185 std::optional<int64_t> stride = parseStrideOrOffset();
1188 strides.push_back(*stride);
1208 std::optional<int64_t> offset = parseStrideOrOffset();
static ParseResult parseElementAttrHexValues(Parser &parser, Token tok, std::string &result)
Parse elements values stored within a hex string.
static std::optional< APInt > buildAttributeAPInt(Type type, bool isNegative, StringRef spelling)
Construct an APint from a parsed value, a known attribute type and sign.
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
static ArrayRef< int64_t > getShape(Type type)
Returns the shape of the given type.
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
void addUses(Value value, ArrayRef< SMLoc > locations)
Add a source uses of the given value.
@ Braces
{} brackets surrounding zero or more operands.
@ Square
Square brackets surrounding zero or more operands.
Attributes are known-constant values of operations.
IntegerAttr getIntegerAttr(Type type, int64_t value)
IntegerType getIntegerType(unsigned width)
BoolAttr getBoolAttr(bool value)
StringAttr getStringAttr(const Twine &bytes)
ArrayAttr getArrayAttr(ArrayRef< Attribute > value)
An attribute that represents a reference to a dense vector or tensor object.
static DenseElementsAttr getFromRawBuffer(ShapedType type, ArrayRef< char > rawBuffer)
Construct a dense elements attribute from a raw buffer representing the data for this attribute.
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
static bool isValidRawBuffer(ShapedType type, ArrayRef< char > rawBuffer, bool &detectedSplat)
Returns true if the given buffer is a valid raw buffer for the given type.
This class provides support for representing a failure result, or a valid value of type T.
const llvm::fltSemantics & getFloatSemantics()
Return the floating semantics of this float type.
unsigned getWidth()
Return the bitwidth of this float type.
An integer set representing a conjunction of one or more affine equalities and inequalities.
void resetPointer(const char *newPointer)
Change the position of the lexer cursor.
Location objects represent source locations information in MLIR.
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 class represents success/failure for parsing-like operations that find it important to chain tog...
This represents a token in the MLIR syntax.
bool isKeyword() const
Return true if this is one of the keyword token kinds (e.g. kw_if).
std::string getStringValue() const
Given a token containing a string literal, return its value, including removing the quote characters ...
std::string getSymbolReference() const
Given a token containing a symbol reference, return the unescaped string value.
static std::optional< uint64_t > getUInt64IntegerValue(StringRef spelling)
For an integer token, return its value as an uint64_t.
std::optional< double > getFloatingPointValue() const
For a floatliteral token, return its value as a double.
bool isAny(Kind k1, Kind k2) const
StringRef getSpelling() const
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...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
bool isInteger(unsigned width) const
Return true if this is an integer type with the specified width.
bool isSignedInteger() const
Return true if this is a signed integer type (with the specified width).
bool isIntOrIndexOrFloat() const
Return true if this is an integer (of any signedness), index, or float type.
bool isUnsignedInteger() const
Return true if this is an unsigned integer type (with the specified width).
bool isIntOrIndex() const
Return true if this is an integer (of any signedness) or an index type.
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
This class implement support for parsing global entities like attributes and types.
Attribute parseDenseArrayAttr(Type type)
Parse a DenseArrayAttr.
Attribute parseStridedLayoutAttr()
Parse a strided layout attribute.
Attribute parseDecOrHexAttr(Type type, bool isNegative)
Parse a decimal or a hexadecimal literal, which can be either an integer or a float attribute.
OptionalParseResult parseOptionalType(Type &type)
Optionally parse a type.
ParseResult parseToken(Token::Kind expectedToken, const Twine &message)
Consume the specified token if present and return success.
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.
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.
ParserState & state
The Parser is subclassed and reinstantiated.
Attribute parseAttribute(Type type={})
Parse an arbitrary attribute with an optional type.
StringRef getTokenSpelling() const
ParseResult parseLocationInstance(LocationAttr &loc)
Parse a raw location instance.
void consumeToken()
Advance the current lexer onto the next token.
Attribute codeCompleteAttribute()
ParseResult parseAttributeDict(NamedAttrList &attributes)
Parse an attribute dictionary.
ShapedType parseElementsLiteralType(Type type)
Shaped type for elements attribute.
MLIRContext * getContext() const
InFlightDiagnostic emitWrongTokenError(const Twine &message={})
Emit an error about a "wrong token".
ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())
Parse a list of comma-separated items with an optional delimiter.
Attribute parseSparseElementsAttr(Type attrType)
Parse a sparse elements attribute.
OptionalParseResult parseOptionalAttribute(Attribute &attribute, Type type={})
Parse an optional attribute with the provided type.
ParseResult parseFloatFromIntegerLiteral(std::optional< APFloat > &result, const Token &tok, bool isNegative, const llvm::fltSemantics &semantics, size_t typeSizeInBits)
Parse a floating point value from an integer literal token.
Attribute parseFloatAttr(Type type, bool isNegative)
Parse a float attribute.
ParseResult parseIntegerSetReference(IntegerSet &set)
Attribute parseExtendedAttr(Type type)
Parse an extended attribute.
const Token & getToken() const
Return the current token the parser is inspecting.
FailureOr< AsmDialectResourceHandle > parseResourceHandle(const OpAsmDialectInterface *dialect, StringRef &name)
Parse a handle to a dialect resource within the assembly format.
bool consumeIf(Token::Kind kind)
If the current token has the specified kind, consume it and return true.
OptionalParseResult parseOptionalAttributeWithToken(Token::Kind kind, AttributeT &attr, Type type={})
Parse an optional attribute that is demarcated by a specific token.
Detect if any of the given parameter types has a sub-element handler.
This header declares functions that assit transformations in the MemRef dialect.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
Lexer lex
The lexer for the source file we're parsing.
AsmParserState * asmState
An optional pointer to a struct containing high level parser state to be populated during parsing.