22#include "llvm/Support/ErrorHandling.h"
23#include "llvm/Support/MemoryBuffer.h"
24#include "llvm/Support/SourceMgr.h"
25#include "llvm/Support/raw_ostream.h"
47enum AffineHighPrecOp {
59class AffineParser :
public Parser {
61 AffineParser(ParserState &state,
bool allowParsingSSAIds =
false,
63 : Parser(state), allowParsingSSAIds(allowParsingSSAIds),
64 parseElement(parseElement) {}
66 ParseResult parseAffineMapRange(
unsigned numDims,
unsigned numSymbols,
68 ParseResult parseAffineMapOrIntegerSetInline(AffineMap &map, IntegerSet &set);
70 parseAffineExprInline(ArrayRef<std::pair<StringRef, AffineExpr>> symbolSet,
72 ParseResult parseIntegerSetConstraints(
unsigned numDims,
unsigned numSymbols,
74 ParseResult parseAffineMapOfSSAIds(AffineMap &map,
75 OpAsmParser::Delimiter delimiter);
76 ParseResult parseAffineExprOfSSAIds(AffineExpr &expr);
80 AffineLowPrecOp consumeIfLowPrecOp();
81 AffineHighPrecOp consumeIfHighPrecOp();
84 ParseResult parseDimIdList(
unsigned &numDims);
85 ParseResult parseSymbolIdList(
unsigned &numSymbols);
86 ParseResult parseDimAndOptionalSymbolIdList(
unsigned &numDims,
87 unsigned &numSymbols);
88 ParseResult parseIdentifierDefinition(AffineExpr idExpr);
90 AffineExpr parseAffineExpr();
91 AffineExpr parseParentheticalExpr();
92 AffineExpr parseNegateExpression(AffineExpr
lhs);
93 AffineExpr parseIntegerExpr();
94 AffineExpr parseBareIdExpr();
95 AffineExpr parseSSAIdExpr(
bool isSymbol);
96 AffineExpr parseSymbolSSAIdExpr();
99 AffineExpr
rhs, SMLoc opLoc);
102 AffineExpr parseAffineOperandExpr(AffineExpr
lhs);
103 AffineExpr parseAffineLowPrecOpExpr(AffineExpr llhs, AffineLowPrecOp llhsOp);
104 AffineExpr parseAffineHighPrecOpExpr(AffineExpr llhs, AffineHighPrecOp llhsOp,
106 AffineExpr parseAffineConstraint(
bool *isEq);
109 bool allowParsingSSAIds;
111 unsigned numDimOperands = 0;
112 unsigned numSymbolOperands = 0;
113 SmallVector<std::pair<StringRef, AffineExpr>, 4> dimsAndSymbols;
120AffineExpr AffineParser::getAffineBinaryOpExpr(AffineHighPrecOp op,
126 if (!
lhs.isSymbolicOrConstant() && !
rhs.isSymbolicOrConstant()) {
127 emitError(opLoc,
"non-affine expression: at least one of the multiply "
128 "operands has to be either a constant or symbolic");
133 if (!
rhs.isSymbolicOrConstant()) {
134 emitError(opLoc,
"non-affine expression: right operand of floordiv "
135 "has to be either a constant or symbolic");
140 if (!
rhs.isSymbolicOrConstant()) {
141 emitError(opLoc,
"non-affine expression: right operand of ceildiv "
142 "has to be either a constant or symbolic");
147 if (!
rhs.isSymbolicOrConstant()) {
148 emitError(opLoc,
"non-affine expression: right operand of mod "
149 "has to be either a constant or symbolic");
154 llvm_unreachable(
"can't create affine expression for null high prec op");
157 llvm_unreachable(
"Unknown AffineHighPrecOp");
161AffineExpr AffineParser::getAffineBinaryOpExpr(AffineLowPrecOp op,
162 AffineExpr
lhs, AffineExpr
rhs) {
164 case AffineLowPrecOp::Add:
166 case AffineLowPrecOp::Sub:
168 case AffineLowPrecOp::LNoOp:
169 llvm_unreachable(
"can't create affine expression for null low prec op");
172 llvm_unreachable(
"Unknown AffineLowPrecOp");
177AffineLowPrecOp AffineParser::consumeIfLowPrecOp() {
178 switch (getToken().getKind()) {
180 consumeToken(Token::plus);
181 return AffineLowPrecOp::Add;
183 consumeToken(Token::minus);
184 return AffineLowPrecOp::Sub;
186 return AffineLowPrecOp::LNoOp;
192AffineHighPrecOp AffineParser::consumeIfHighPrecOp() {
193 switch (getToken().getKind()) {
195 consumeToken(Token::star);
197 case Token::kw_floordiv:
198 consumeToken(Token::kw_floordiv);
200 case Token::kw_ceildiv:
201 consumeToken(Token::kw_ceildiv);
204 consumeToken(Token::kw_mod);
220AffineExpr AffineParser::parseAffineHighPrecOpExpr(AffineExpr llhs,
221 AffineHighPrecOp llhsOp,
223 AffineExpr
lhs = parseAffineOperandExpr(llhs);
228 auto opLoc = getToken().getLoc();
229 if (AffineHighPrecOp op = consumeIfHighPrecOp()) {
234 return parseAffineHighPrecOpExpr(expr, op, opLoc);
237 return parseAffineHighPrecOpExpr(
lhs, op, opLoc);
251AffineExpr AffineParser::parseParentheticalExpr() {
252 if (parseToken(Token::l_paren,
"expected '('"))
254 if (getToken().is(Token::r_paren))
255 return emitError(
"no expression inside parentheses"),
nullptr;
257 auto expr = parseAffineExpr();
258 if (!expr || parseToken(Token::r_paren,
"expected ')'"))
267AffineExpr AffineParser::parseNegateExpression(AffineExpr
lhs) {
268 if (parseToken(Token::minus,
"expected '-'"))
271 AffineExpr operand = parseAffineOperandExpr(
lhs);
278 return emitError(
"missing operand of negation"),
nullptr;
279 return (-1) * operand;
286 return token.
isAny(Token::bare_identifier, Token::inttype) ||
293AffineExpr AffineParser::parseBareIdExpr() {
295 return emitWrongTokenError(
"expected bare identifier"),
nullptr;
297 StringRef sRef = getTokenSpelling();
298 for (
auto entry : dimsAndSymbols) {
299 if (entry.first == sRef) {
305 return emitWrongTokenError(
"use of undeclared identifier"),
nullptr;
309AffineExpr AffineParser::parseSSAIdExpr(
bool isSymbol) {
310 if (!allowParsingSSAIds)
311 return emitWrongTokenError(
"unexpected ssa identifier"),
nullptr;
312 if (getToken().isNot(Token::percent_identifier))
313 return emitWrongTokenError(
"expected ssa identifier"),
nullptr;
314 auto name = getTokenSpelling();
316 for (
auto entry : dimsAndSymbols) {
317 if (entry.first == name) {
318 consumeToken(Token::percent_identifier);
323 if (parseElement(isSymbol))
325 auto idExpr = isSymbol
328 dimsAndSymbols.push_back({name, idExpr});
332AffineExpr AffineParser::parseSymbolSSAIdExpr() {
333 if (parseToken(Token::kw_symbol,
"expected symbol keyword") ||
334 parseToken(Token::l_paren,
"expected '(' at start of SSA symbol"))
336 AffineExpr symbolExpr = parseSSAIdExpr(
true);
339 if (parseToken(Token::r_paren,
"expected ')' at end of SSA symbol"))
347AffineExpr AffineParser::parseIntegerExpr() {
348 auto val = getToken().getUInt64IntegerValue();
354 if (!val.has_value() ||
355 (
static_cast<int64_t
>(*val) < 0 &&
356 *val !=
static_cast<uint64_t
>(std::numeric_limits<int64_t>::min())))
357 return emitError(
"constant too large for index"),
nullptr;
359 consumeToken(Token::integer);
360 return builder.getAffineConstantExpr((int64_t)*val);
372AffineExpr AffineParser::parseAffineOperandExpr(AffineExpr
lhs) {
373 switch (getToken().getKind()) {
374 case Token::kw_symbol:
375 return parseSymbolSSAIdExpr();
376 case Token::percent_identifier:
377 return parseSSAIdExpr(
false);
379 return parseIntegerExpr();
381 return parseParentheticalExpr();
383 return parseNegateExpression(
lhs);
384 case Token::kw_ceildiv:
385 case Token::kw_floordiv:
388 return parseBareIdExpr();
392 emitError(
"missing right operand of binary operator");
394 emitError(
"missing left operand of binary operator");
399 return parseBareIdExpr();
402 emitError(
"missing right operand of binary operator");
430AffineExpr AffineParser::parseAffineLowPrecOpExpr(AffineExpr llhs,
431 AffineLowPrecOp llhsOp) {
433 if (!(
lhs = parseAffineOperandExpr(llhs)))
437 if (AffineLowPrecOp lOp = consumeIfLowPrecOp()) {
440 return parseAffineLowPrecOpExpr(sum, lOp);
443 return parseAffineLowPrecOpExpr(
lhs, lOp);
445 auto opLoc = getToken().getLoc();
446 if (AffineHighPrecOp hOp = consumeIfHighPrecOp()) {
449 AffineExpr highRes = parseAffineHighPrecOpExpr(
lhs, hOp, opLoc);
460 if (AffineLowPrecOp nextOp = consumeIfLowPrecOp())
461 return parseAffineLowPrecOpExpr(expr, nextOp);
486AffineExpr AffineParser::parseAffineExpr() {
487 return parseAffineLowPrecOpExpr(
nullptr, AffineLowPrecOp::LNoOp);
493ParseResult AffineParser::parseIdentifierDefinition(AffineExpr idExpr) {
495 return emitWrongTokenError(
"expected bare identifier");
497 auto name = getTokenSpelling();
498 for (
auto entry : dimsAndSymbols) {
499 if (entry.first == name)
500 return emitError(
"redefinition of identifier '" + name +
"'");
504 dimsAndSymbols.push_back({name, idExpr});
509ParseResult AffineParser::parseDimIdList(
unsigned &numDims) {
510 auto parseElt = [&]() -> ParseResult {
512 return parseIdentifierDefinition(dimension);
515 " in dimensional identifier list");
519ParseResult AffineParser::parseSymbolIdList(
unsigned &numSymbols) {
520 auto parseElt = [&]() -> ParseResult {
522 return parseIdentifierDefinition(symbol);
530AffineParser::parseDimAndOptionalSymbolIdList(
unsigned &numDims,
531 unsigned &numSymbols) {
532 if (parseDimIdList(numDims)) {
535 if (!getToken().is(Token::l_square)) {
539 return parseSymbolIdList(numSymbols);
543ParseResult AffineParser::parseAffineMapOrIntegerSetInline(AffineMap &map,
545 unsigned numDims = 0, numSymbols = 0;
548 if (parseDimAndOptionalSymbolIdList(numDims, numSymbols))
551 if (consumeIf(Token::arrow))
552 return parseAffineMapRange(numDims, numSymbols, map);
554 if (parseToken(Token::colon,
"expected '->' or ':'"))
556 return parseIntegerSetConstraints(numDims, numSymbols, set);
560ParseResult AffineParser::parseAffineExprInline(
561 ArrayRef<std::pair<StringRef, AffineExpr>> symbolSet, AffineExpr &expr) {
562 dimsAndSymbols.assign(symbolSet.begin(), symbolSet.end());
563 expr = parseAffineExpr();
564 return success(expr !=
nullptr);
569AffineParser::parseAffineMapOfSSAIds(AffineMap &map,
570 OpAsmParser::Delimiter delimiter) {
572 SmallVector<AffineExpr, 4> exprs;
573 auto parseElt = [&]() -> ParseResult {
574 auto elt = parseAffineExpr();
575 exprs.push_back(elt);
576 return elt ?
success() : failure();
587 map =
AffineMap::get(numDimOperands, dimsAndSymbols.size() - numDimOperands,
593ParseResult AffineParser::parseAffineExprOfSSAIds(AffineExpr &expr) {
594 expr = parseAffineExpr();
595 return success(expr !=
nullptr);
604ParseResult AffineParser::parseAffineMapRange(
unsigned numDims,
607 SmallVector<AffineExpr, 4> exprs;
608 auto parseElt = [&]() -> ParseResult {
609 auto elt = parseAffineExpr();
610 ParseResult res = elt ?
success() : failure();
611 exprs.push_back(elt);
620 " in affine map range"))
641AffineExpr AffineParser::parseAffineConstraint(
bool *isEq) {
642 AffineExpr lhsExpr = parseAffineExpr();
647 if (consumeIf(Token::greater) && consumeIf(Token::equal)) {
648 AffineExpr rhsExpr = parseAffineExpr();
652 return lhsExpr - rhsExpr;
656 if (consumeIf(Token::less) && consumeIf(Token::equal)) {
657 AffineExpr rhsExpr = parseAffineExpr();
661 return rhsExpr - lhsExpr;
665 if (consumeIf(Token::equal) && consumeIf(Token::equal)) {
666 AffineExpr rhsExpr = parseAffineExpr();
670 return lhsExpr - rhsExpr;
673 return emitError(
"expected '== affine-expr' or '>= affine-expr' at end of "
674 "affine constraint"),
685ParseResult AffineParser::parseIntegerSetConstraints(
unsigned numDims,
688 SmallVector<AffineExpr, 4> constraints;
689 SmallVector<bool, 4> isEqs;
690 auto parseElt = [&]() -> ParseResult {
692 auto elt = parseAffineConstraint(&isEq);
693 ParseResult res = elt ?
success() : failure();
695 constraints.push_back(elt);
696 isEqs.push_back(isEq);
703 " in integer set constraint list"))
707 if (constraints.empty()) {
726 return AffineParser(
state).parseAffineMapOrIntegerSetInline(map, set);
734 return emitError(curLoc,
"expected AffineMap, but got IntegerSet");
739 return AffineParser(
state).parseAffineExprInline(symbolSet, expr);
747 return emitError(curLoc,
"expected IntegerSet, but got AffineMap");
757 return AffineParser(
state,
true, parseElement)
758 .parseAffineMapOfSSAIds(map, delimiter);
766 return AffineParser(
state,
true, parseElement)
767 .parseAffineExprOfSSAIds(expr);
772 llvm::SourceMgr sourceMgr;
773 auto memBuffer = llvm::MemoryBuffer::getMemBuffer(
774 inputStr,
"<mlir_parser_buffer>",
776 sourceMgr.AddNewSourceBuffer(std::move(memBuffer), SMLoc());
779 ParserState state(sourceMgr, config, symbolState,
nullptr,
788 if (endTok.
isNot(Token::eof)) {
799 "expected string to represent AffineMap, but got IntegerSet instead");
808 "expected string to represent IntegerSet, but got AffineMap instead");
static bool isIdentifier(const Token &token)
Returns true if the given token can be represented as an identifier.
static void parseAffineMapOrIntegerSet(StringRef inputStr, MLIRContext *context, AffineMap &map, IntegerSet &set)
Base type for affine expression.
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
Delimiter
These are the supported delimiters around operand lists and region argument lists,...
An integer set representing a conjunction of one or more affine equalities and inequalities.
static IntegerSet get(unsigned dimCount, unsigned symbolCount, ArrayRef< AffineExpr > constraints, ArrayRef< bool > eqFlags)
MLIRContext is the top-level object for a collection of MLIR operations.
This class represents a configuration for the MLIR assembly parser.
This class is a utility diagnostic handler for use with llvm::SourceMgr.
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).
bool isAny(Kind k1, Kind k2) const
This class implement support for parsing global entities like attributes and types.
ParseResult parseAffineMapReference(AffineMap &map)
InFlightDiagnostic emitError(const Twine &message={})
Emit an error and return failure.
ParserState & state
The Parser is subclassed and reinstantiated.
ParseResult parseAffineMapOrIntegerSetReference(AffineMap &map, IntegerSet &set)
Parse a reference to either an affine map, expr, or an integer set.
ParseResult parseAffineMapOfSSAIds(AffineMap &map, function_ref< ParseResult(bool)> parseElement, Delimiter delimiter)
Parse an AffineMap where the dim and symbol identifiers are SSA ids.
ParseResult parseIntegerSetReference(IntegerSet &set)
ParseResult parseAffineExprReference(ArrayRef< std::pair< StringRef, AffineExpr > > symbolSet, AffineExpr &expr)
const Token & getToken() const
Return the current token the parser is inspecting.
ParseResult parseAffineExprOfSSAIds(AffineExpr &expr, function_ref< ParseResult(bool)> parseElement)
Parse an AffineExpr where dim and symbol identifiers are SSA ids.
LogicalResult parseCommaSeparatedList(llvm::cl::Option &opt, StringRef argName, StringRef optionStr, function_ref< LogicalResult(StringRef)> elementParseFn)
Parse a string containing a list of comma-delimited elements, invoking the given parser for each sub-...
Include the generated interface declarations.
AffineMap parseAffineMap(llvm::StringRef str, MLIRContext *context)
This parses a single IntegerSet/AffineMap to an MLIR context if it was valid.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
@ CeilDiv
RHS of ceildiv is always a constant or a symbolic expression.
@ Mul
RHS of mul is always a constant or a symbolic expression.
@ Mod
RHS of mod is always a constant or a symbolic expression with a positive value.
@ FloorDiv
RHS of floordiv is always a constant or a symbolic expression.
AffineExpr getAffineBinaryOpExpr(AffineExprKind kind, AffineExpr lhs, AffineExpr rhs)
AffineExpr getAffineConstantExpr(int64_t constant, MLIRContext *context)
IntegerSet parseIntegerSet(llvm::StringRef str, MLIRContext *context)
AffineExpr getAffineDimExpr(unsigned position, MLIRContext *context)
These free functions allow clients of the API to not use classes in detail.
llvm::function_ref< Fn > function_ref
AffineExpr getAffineSymbolExpr(unsigned position, MLIRContext *context)
This class refers to all of the state maintained globally by the parser, such as the current lexer po...
This class contains record of any parsed top-level symbols.