Add parsing for attributes and attibutes on operations. Add IR representation
for attributes on operations. Split Operation out from OperationInst so it
can be shared with OperationStmt one day.
PiperOrigin-RevId: 203325366
diff --git a/lib/Parser/Parser.cpp b/lib/Parser/Parser.cpp
index 8c44bbd..a4d532f 100644
--- a/lib/Parser/Parser.cpp
+++ b/lib/Parser/Parser.cpp
@@ -18,12 +18,12 @@
// This file implements the parser for the MLIR textual form.
//
//===----------------------------------------------------------------------===//
-#include <stack>
#include "mlir/Parser.h"
#include "Lexer.h"
#include "mlir/IR/AffineExpr.h"
#include "mlir/IR/AffineMap.h"
+#include "mlir/IR/Attributes.h"
#include "mlir/IR/CFGFunction.h"
#include "mlir/IR/Module.h"
#include "mlir/IR/MLFunction.h"
@@ -92,9 +92,7 @@
std::unique_ptr<Module> module;
// A map from affine map identifier to AffineMap.
- // TODO(andydavis) Remove use of unique_ptr when AffineMaps are bump pointer
- // allocated.
- llvm::StringMap<std::unique_ptr<AffineMap>> affineMaps;
+ llvm::StringMap<AffineMap*> affineMapDefinitions;
private:
// Helper methods.
@@ -153,6 +151,10 @@
Type *parseType();
ParseResult parseTypeList(SmallVectorImpl<Type*> &elements);
+ // Attribute parsing.
+ Attribute *parseAttribute();
+ ParseResult parseAttributeDict(SmallVectorImpl<NamedAttribute> &attributes);
+
// Parsing identifiers' lists for polyhedral structures.
ParseResult parseDimIdList(AffineMapParserState &state);
ParseResult parseSymbolIdList(AffineMapParserState &state);
@@ -160,7 +162,7 @@
// Polyhedral structures.
ParseResult parseAffineMapDef();
- ParseResult parseAffineMapInline(StringRef mapId, AffineMap *&affineMap);
+ AffineMap *parseAffineMapInline(StringRef mapId);
AffineExpr *parseAffineExpr(const AffineMapParserState &state);
AffineExpr *parseParentheticalExpr(const AffineMapParserState &state);
@@ -543,6 +545,110 @@
} // end anonymous namespace
//===----------------------------------------------------------------------===//
+// Attribute parsing.
+//===----------------------------------------------------------------------===//
+
+
+/// Attribute parsing.
+///
+/// attribute-value ::= bool-literal
+/// | integer-literal
+/// | float-literal
+/// | string-literal
+/// | `[` (attribute-value (`,` attribute-value)*)? `]`
+///
+Attribute *Parser::parseAttribute() {
+ switch (curToken.getKind()) {
+ case Token::kw_true:
+ consumeToken(Token::kw_true);
+ return BoolAttr::get(true, context);
+ case Token::kw_false:
+ consumeToken(Token::kw_false);
+ return BoolAttr::get(false, context);
+
+ case Token::integer: {
+ auto val = curToken.getUInt64IntegerValue();
+ if (!val.hasValue() || (int64_t)val.getValue() < 0)
+ return (emitError("integer too large for attribute"), nullptr);
+ consumeToken(Token::integer);
+ return IntegerAttr::get((int64_t)val.getValue(), context);
+ }
+
+ case Token::minus: {
+ consumeToken(Token::minus);
+ if (curToken.is(Token::integer)) {
+ auto val = curToken.getUInt64IntegerValue();
+ if (!val.hasValue() || (int64_t)-val.getValue() >= 0)
+ return (emitError("integer too large for attribute"), nullptr);
+ consumeToken(Token::integer);
+ return IntegerAttr::get((int64_t)-val.getValue(), context);
+ }
+
+ return (emitError("expected constant integer or floating point value"),
+ nullptr);
+ }
+
+ case Token::string: {
+ auto val = curToken.getStringValue();
+ consumeToken(Token::string);
+ return StringAttr::get(val, context);
+ }
+
+ case Token::l_bracket: {
+ consumeToken(Token::l_bracket);
+ SmallVector<Attribute*, 4> elements;
+
+ auto parseElt = [&]() -> ParseResult {
+ elements.push_back(parseAttribute());
+ return elements.back() ? ParseSuccess : ParseFailure;
+ };
+
+ if (parseCommaSeparatedList(Token::r_bracket, parseElt))
+ return nullptr;
+ return ArrayAttr::get(elements, context);
+ }
+ default:
+ // TODO: Handle floating point.
+ return (emitError("expected constant attribute value"), nullptr);
+ }
+}
+
+
+/// Attribute dictionary.
+///
+/// attribute-dict ::= `{` `}`
+/// | `{` attribute-entry (`,` attribute-entry)* `}`
+/// attribute-entry ::= bare-id `:` attribute-value
+///
+ParseResult Parser::parseAttributeDict(
+ SmallVectorImpl<NamedAttribute> &attributes) {
+ consumeToken(Token::l_brace);
+
+ auto parseElt = [&]() -> ParseResult {
+ // We allow keywords as attribute names.
+ if (curToken.isNot(Token::bare_identifier, Token::inttype) &&
+ !curToken.isKeyword())
+ return emitError("expected attribute name");
+ auto nameId = Identifier::get(curToken.getSpelling(), context);
+ consumeToken();
+
+ if (!consumeIf(Token::colon))
+ return emitError("expected ':' in attribute list");
+
+ auto attr = parseAttribute();
+ if (!attr) return ParseFailure;
+
+ attributes.push_back({nameId, attr});
+ return ParseSuccess;
+ };
+
+ if (parseCommaSeparatedList(Token::r_brace, parseElt))
+ return ParseFailure;
+
+ return ParseSuccess;
+}
+
+//===----------------------------------------------------------------------===//
// Polyhedral structures.
//===----------------------------------------------------------------------===//
@@ -554,24 +660,23 @@
assert(curToken.is(Token::affine_map_identifier));
StringRef affineMapId = curToken.getSpelling().drop_front();
+
+ // Check for redefinitions.
+ auto *&entry = affineMapDefinitions[affineMapId];
+ if (entry)
+ return emitError("redefinition of affine map id '" + affineMapId + "'");
+
consumeToken(Token::affine_map_identifier);
- // Check that 'affineMapId' is unique.
- // TODO(andydavis) Add a unit test for this case.
- if (affineMaps.count(affineMapId) > 0)
- return emitError("redefinition of affine map id '" + affineMapId + "'");
// Parse the '='
if (!consumeIf(Token::equal))
return emitError("expected '=' in affine map outlined definition");
- AffineMap *affineMap = nullptr;
- if (parseAffineMapInline(affineMapId, affineMap))
+ entry = parseAffineMapInline(affineMapId);
+ if (!entry)
return ParseFailure;
- // TODO(bondhugula): Disable adding affineMapId to Parser::affineMaps for now;
- // instead add to module for easy printing.
- module->affineMapList.push_back(affineMap);
-
+ module->affineMapList.push_back(entry);
return ParseSuccess;
}
@@ -946,25 +1051,24 @@
/// dim-size ::= affine-expr | `min` `(` affine-expr ( `,` affine-expr)+ `)`
///
/// multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
-ParseResult Parser::parseAffineMapInline(StringRef mapId,
- AffineMap *&affineMap) {
+AffineMap *Parser::parseAffineMapInline(StringRef mapId) {
AffineMapParserState state;
// List of dimensional identifiers.
if (parseDimIdList(state))
- return ParseFailure;
+ return nullptr;
// Symbols are optional.
if (curToken.is(Token::l_bracket)) {
if (parseSymbolIdList(state))
- return ParseFailure;
+ return nullptr;
}
if (!consumeIf(Token::arrow)) {
- return (emitError("expected '->' or '['"), ParseFailure);
+ return (emitError("expected '->' or '['"), nullptr);
}
if (!consumeIf(Token::l_paren)) {
emitError("expected '(' at start of affine map range");
- return ParseFailure;
+ return nullptr;
}
SmallVector<AffineExpr *, 4> exprs;
@@ -979,12 +1083,11 @@
// affine expressions); the list cannot be empty.
// Grammar: multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)
if (parseCommaSeparatedList(Token::r_paren, parseElt, false))
- return ParseFailure;
+ return nullptr;
// Parsed a valid affine map.
- affineMap =
- AffineMap::get(state.getNumDims(), state.getNumSymbols(), exprs, context);
- return ParseSuccess;
+ return AffineMap::get(state.getNumDims(), state.getNumSymbols(), exprs,
+ context);
}
//===----------------------------------------------------------------------===//
@@ -1180,14 +1283,20 @@
consumeToken(Token::string);
if (!consumeIf(Token::l_paren))
- return (emitError("expected '(' in operation"), nullptr);
+ return (emitError("expected '(' to start operand list"), nullptr);
// TODO: Parse operands.
if (!consumeIf(Token::r_paren))
- return (emitError("expected '(' in operation"), nullptr);
+ return (emitError("expected ')' in operand list"), nullptr);
+
+ SmallVector<NamedAttribute, 4> attributes;
+ if (curToken.is(Token::l_brace)) {
+ if (parseAttributeDict(attributes))
+ return nullptr;
+ }
auto nameId = Identifier::get(name, context);
- return new OperationInst(nameId);
+ return new OperationInst(nameId, attributes);
}