1 //===- AffineParser.cpp - MLIR Affine Parser ------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements a parser for Affine structures.
11 //===----------------------------------------------------------------------===//
14 #include "ParserState.h"
15 #include "mlir/IR/AffineExpr.h"
16 #include "mlir/IR/AffineMap.h"
17 #include "mlir/IR/AsmState.h"
18 #include "mlir/IR/Diagnostics.h"
19 #include "mlir/IR/IntegerSet.h"
20 #include "mlir/IR/OpImplementation.h"
21 #include "mlir/Support/LLVM.h"
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"
31 using namespace mlir::detail
;
35 /// Lower precedence ops (all at the same precedence level). LNoOp is false in
36 /// the boolean sense.
37 enum AffineLowPrecOp
{
44 /// Higher precedence ops - all at the same precedence level. HNoOp is false
45 /// in the boolean sense.
46 enum AffineHighPrecOp
{
55 /// This is a specialized parser for affine structures (affine maps, affine
56 /// expressions, and integer sets), maintaining the state transient to their
58 class AffineParser
: public Parser
{
60 AffineParser(ParserState
&state
, bool allowParsingSSAIds
= false,
61 function_ref
<ParseResult(bool)> parseElement
= nullptr)
62 : Parser(state
), allowParsingSSAIds(allowParsingSSAIds
),
63 parseElement(parseElement
) {}
65 ParseResult
parseAffineMapRange(unsigned numDims
, unsigned numSymbols
,
67 ParseResult
parseAffineMapOrIntegerSetInline(AffineMap
&map
, IntegerSet
&set
);
69 parseAffineExprInline(ArrayRef
<std::pair
<StringRef
, AffineExpr
>> symbolSet
,
71 ParseResult
parseIntegerSetConstraints(unsigned numDims
, unsigned numSymbols
,
73 ParseResult
parseAffineMapOfSSAIds(AffineMap
&map
,
74 OpAsmParser::Delimiter delimiter
);
75 ParseResult
parseAffineExprOfSSAIds(AffineExpr
&expr
);
78 // Binary affine op parsing.
79 AffineLowPrecOp
consumeIfLowPrecOp();
80 AffineHighPrecOp
consumeIfHighPrecOp();
82 // Identifier lists for polyhedral structures.
83 ParseResult
parseDimIdList(unsigned &numDims
);
84 ParseResult
parseSymbolIdList(unsigned &numSymbols
);
85 ParseResult
parseDimAndOptionalSymbolIdList(unsigned &numDims
,
86 unsigned &numSymbols
);
87 ParseResult
parseIdentifierDefinition(AffineExpr idExpr
);
89 AffineExpr
parseAffineExpr();
90 AffineExpr
parseParentheticalExpr();
91 AffineExpr
parseNegateExpression(AffineExpr lhs
);
92 AffineExpr
parseIntegerExpr();
93 AffineExpr
parseBareIdExpr();
94 AffineExpr
parseSSAIdExpr(bool isSymbol
);
95 AffineExpr
parseSymbolSSAIdExpr();
97 AffineExpr
getAffineBinaryOpExpr(AffineHighPrecOp op
, AffineExpr lhs
,
98 AffineExpr rhs
, SMLoc opLoc
);
99 AffineExpr
getAffineBinaryOpExpr(AffineLowPrecOp op
, AffineExpr lhs
,
101 AffineExpr
parseAffineOperandExpr(AffineExpr lhs
);
102 AffineExpr
parseAffineLowPrecOpExpr(AffineExpr llhs
, AffineLowPrecOp llhsOp
);
103 AffineExpr
parseAffineHighPrecOpExpr(AffineExpr llhs
, AffineHighPrecOp llhsOp
,
105 AffineExpr
parseAffineConstraint(bool *isEq
);
108 bool allowParsingSSAIds
;
109 function_ref
<ParseResult(bool)> parseElement
;
110 unsigned numDimOperands
= 0;
111 unsigned numSymbolOperands
= 0;
112 SmallVector
<std::pair
<StringRef
, AffineExpr
>, 4> dimsAndSymbols
;
116 /// Create an affine binary high precedence op expression (mul's, div's, mod).
117 /// opLoc is the location of the op token to be used to report errors
118 /// for non-conforming expressions.
119 AffineExpr
AffineParser::getAffineBinaryOpExpr(AffineHighPrecOp op
,
120 AffineExpr lhs
, AffineExpr rhs
,
122 // TODO: make the error location info accurate.
125 if (!lhs
.isSymbolicOrConstant() && !rhs
.isSymbolicOrConstant()) {
126 emitError(opLoc
, "non-affine expression: at least one of the multiply "
127 "operands has to be either a constant or symbolic");
132 if (!rhs
.isSymbolicOrConstant()) {
133 emitError(opLoc
, "non-affine expression: right operand of floordiv "
134 "has to be either a constant or symbolic");
137 return lhs
.floorDiv(rhs
);
139 if (!rhs
.isSymbolicOrConstant()) {
140 emitError(opLoc
, "non-affine expression: right operand of ceildiv "
141 "has to be either a constant or symbolic");
144 return lhs
.ceilDiv(rhs
);
146 if (!rhs
.isSymbolicOrConstant()) {
147 emitError(opLoc
, "non-affine expression: right operand of mod "
148 "has to be either a constant or symbolic");
153 llvm_unreachable("can't create affine expression for null high prec op");
156 llvm_unreachable("Unknown AffineHighPrecOp");
159 /// Create an affine binary low precedence op expression (add, sub).
160 AffineExpr
AffineParser::getAffineBinaryOpExpr(AffineLowPrecOp op
,
161 AffineExpr lhs
, AffineExpr rhs
) {
163 case AffineLowPrecOp::Add
:
165 case AffineLowPrecOp::Sub
:
167 case AffineLowPrecOp::LNoOp
:
168 llvm_unreachable("can't create affine expression for null low prec op");
171 llvm_unreachable("Unknown AffineLowPrecOp");
174 /// Consume this token if it is a lower precedence affine op (there are only
175 /// two precedence levels).
176 AffineLowPrecOp
AffineParser::consumeIfLowPrecOp() {
177 switch (getToken().getKind()) {
179 consumeToken(Token::plus
);
180 return AffineLowPrecOp::Add
;
182 consumeToken(Token::minus
);
183 return AffineLowPrecOp::Sub
;
185 return AffineLowPrecOp::LNoOp
;
189 /// Consume this token if it is a higher precedence affine op (there are only
190 /// two precedence levels)
191 AffineHighPrecOp
AffineParser::consumeIfHighPrecOp() {
192 switch (getToken().getKind()) {
194 consumeToken(Token::star
);
196 case Token::kw_floordiv
:
197 consumeToken(Token::kw_floordiv
);
199 case Token::kw_ceildiv
:
200 consumeToken(Token::kw_ceildiv
);
203 consumeToken(Token::kw_mod
);
210 /// Parse a high precedence op expression list: mul, div, and mod are high
211 /// precedence binary ops, i.e., parse a
212 /// expr_1 op_1 expr_2 op_2 ... expr_n
213 /// where op_1, op_2 are all a AffineHighPrecOp (mul, div, mod).
214 /// All affine binary ops are left associative.
215 /// Given llhs, returns (llhs llhsOp lhs) op rhs, or (lhs op rhs) if llhs is
216 /// null. If no rhs can be found, returns (llhs llhsOp lhs) or lhs if llhs is
217 /// null. llhsOpLoc is the location of the llhsOp token that will be used to
218 /// report an error for non-conforming expressions.
219 AffineExpr
AffineParser::parseAffineHighPrecOpExpr(AffineExpr llhs
,
220 AffineHighPrecOp llhsOp
,
222 AffineExpr lhs
= parseAffineOperandExpr(llhs
);
226 // Found an LHS. Parse the remaining expression.
227 auto opLoc
= getToken().getLoc();
228 if (AffineHighPrecOp op
= consumeIfHighPrecOp()) {
230 AffineExpr expr
= getAffineBinaryOpExpr(llhsOp
, llhs
, lhs
, opLoc
);
233 return parseAffineHighPrecOpExpr(expr
, op
, opLoc
);
236 return parseAffineHighPrecOpExpr(lhs
, op
, opLoc
);
239 // This is the last operand in this expression.
241 return getAffineBinaryOpExpr(llhsOp
, llhs
, lhs
, llhsOpLoc
);
243 // No llhs, 'lhs' itself is the expression.
247 /// Parse an affine expression inside parentheses.
249 /// affine-expr ::= `(` affine-expr `)`
250 AffineExpr
AffineParser::parseParentheticalExpr() {
251 if (parseToken(Token::l_paren
, "expected '('"))
253 if (getToken().is(Token::r_paren
))
254 return emitError("no expression inside parentheses"), nullptr;
256 auto expr
= parseAffineExpr();
257 if (!expr
|| parseToken(Token::r_paren
, "expected ')'"))
263 /// Parse the negation expression.
265 /// affine-expr ::= `-` affine-expr
266 AffineExpr
AffineParser::parseNegateExpression(AffineExpr lhs
) {
267 if (parseToken(Token::minus
, "expected '-'"))
270 AffineExpr operand
= parseAffineOperandExpr(lhs
);
271 // Since negation has the highest precedence of all ops (including high
272 // precedence ops) but lower than parentheses, we are only going to use
273 // parseAffineOperandExpr instead of parseAffineExpr here.
275 // Extra error message although parseAffineOperandExpr would have
276 // complained. Leads to a better diagnostic.
277 return emitError("missing operand of negation"), nullptr;
278 return (-1) * operand
;
281 /// Returns true if the given token can be represented as an identifier.
282 static bool isIdentifier(const Token
&token
) {
283 // We include only `inttype` and `bare_identifier` here since they are the
284 // only non-keyword tokens that can be used to represent an identifier.
285 return token
.isAny(Token::bare_identifier
, Token::inttype
) ||
289 /// Parse a bare id that may appear in an affine expression.
291 /// affine-expr ::= bare-id
292 AffineExpr
AffineParser::parseBareIdExpr() {
293 if (!isIdentifier(getToken()))
294 return emitWrongTokenError("expected bare identifier"), nullptr;
296 StringRef sRef
= getTokenSpelling();
297 for (auto entry
: dimsAndSymbols
) {
298 if (entry
.first
== sRef
) {
304 return emitWrongTokenError("use of undeclared identifier"), nullptr;
307 /// Parse an SSA id which may appear in an affine expression.
308 AffineExpr
AffineParser::parseSSAIdExpr(bool isSymbol
) {
309 if (!allowParsingSSAIds
)
310 return emitWrongTokenError("unexpected ssa identifier"), nullptr;
311 if (getToken().isNot(Token::percent_identifier
))
312 return emitWrongTokenError("expected ssa identifier"), nullptr;
313 auto name
= getTokenSpelling();
314 // Check if we already parsed this SSA id.
315 for (auto entry
: dimsAndSymbols
) {
316 if (entry
.first
== name
) {
317 consumeToken(Token::percent_identifier
);
321 // Parse the SSA id and add an AffineDim/SymbolExpr to represent it.
322 if (parseElement(isSymbol
))
324 auto idExpr
= isSymbol
325 ? getAffineSymbolExpr(numSymbolOperands
++, getContext())
326 : getAffineDimExpr(numDimOperands
++, getContext());
327 dimsAndSymbols
.push_back({name
, idExpr
});
331 AffineExpr
AffineParser::parseSymbolSSAIdExpr() {
332 if (parseToken(Token::kw_symbol
, "expected symbol keyword") ||
333 parseToken(Token::l_paren
, "expected '(' at start of SSA symbol"))
335 AffineExpr symbolExpr
= parseSSAIdExpr(/*isSymbol=*/true);
338 if (parseToken(Token::r_paren
, "expected ')' at end of SSA symbol"))
343 /// Parse a positive integral constant appearing in an affine expression.
345 /// affine-expr ::= integer-literal
346 AffineExpr
AffineParser::parseIntegerExpr() {
347 auto val
= getToken().getUInt64IntegerValue();
348 if (!val
.has_value() || (int64_t)*val
< 0)
349 return emitError("constant too large for index"), nullptr;
351 consumeToken(Token::integer
);
352 return builder
.getAffineConstantExpr((int64_t)*val
);
355 /// Parses an expression that can be a valid operand of an affine expression.
356 /// lhs: if non-null, lhs is an affine expression that is the lhs of a binary
357 /// operator, the rhs of which is being parsed. This is used to determine
358 /// whether an error should be emitted for a missing right operand.
359 // Eg: for an expression without parentheses (like i + j + k + l), each
360 // of the four identifiers is an operand. For i + j*k + l, j*k is not an
361 // operand expression, it's an op expression and will be parsed via
362 // parseAffineHighPrecOpExpression(). However, for i + (j*k) + -l, (j*k) and
363 // -l are valid operands that will be parsed by this function.
364 AffineExpr
AffineParser::parseAffineOperandExpr(AffineExpr lhs
) {
365 switch (getToken().getKind()) {
366 case Token::kw_symbol
:
367 return parseSymbolSSAIdExpr();
368 case Token::percent_identifier
:
369 return parseSSAIdExpr(/*isSymbol=*/false);
371 return parseIntegerExpr();
373 return parseParentheticalExpr();
375 return parseNegateExpression(lhs
);
376 case Token::kw_ceildiv
:
377 case Token::kw_floordiv
:
379 // Try to treat these tokens as identifiers.
380 return parseBareIdExpr();
384 emitError("missing right operand of binary operator");
386 emitError("missing left operand of binary operator");
389 // If nothing matches, we try to treat this token as an identifier.
390 if (isIdentifier(getToken()))
391 return parseBareIdExpr();
394 emitError("missing right operand of binary operator");
396 emitError("expected affine expression");
401 /// Parse affine expressions that are bare-id's, integer constants,
402 /// parenthetical affine expressions, and affine op expressions that are a
403 /// composition of those.
405 /// All binary op's associate from left to right.
407 /// {add, sub} have lower precedence than {mul, div, and mod}.
409 /// Add, sub'are themselves at the same precedence level. Mul, floordiv,
410 /// ceildiv, and mod are at the same higher precedence level. Negation has
411 /// higher precedence than any binary op.
413 /// llhs: the affine expression appearing on the left of the one being parsed.
414 /// This function will return ((llhs llhsOp lhs) op rhs) if llhs is non null,
415 /// and lhs op rhs otherwise; if there is no rhs, llhs llhsOp lhs is returned
416 /// if llhs is non-null; otherwise lhs is returned. This is to deal with left
419 /// Eg: when the expression is e1 + e2*e3 + e4, with e1 as llhs, this function
420 /// will return the affine expr equivalent of (e1 + (e2*e3)) + e4, where
421 /// (e2*e3) will be parsed using parseAffineHighPrecOpExpr().
422 AffineExpr
AffineParser::parseAffineLowPrecOpExpr(AffineExpr llhs
,
423 AffineLowPrecOp llhsOp
) {
425 if (!(lhs
= parseAffineOperandExpr(llhs
)))
428 // Found an LHS. Deal with the ops.
429 if (AffineLowPrecOp lOp
= consumeIfLowPrecOp()) {
431 AffineExpr sum
= getAffineBinaryOpExpr(llhsOp
, llhs
, lhs
);
432 return parseAffineLowPrecOpExpr(sum
, lOp
);
434 // No LLHS, get RHS and form the expression.
435 return parseAffineLowPrecOpExpr(lhs
, lOp
);
437 auto opLoc
= getToken().getLoc();
438 if (AffineHighPrecOp hOp
= consumeIfHighPrecOp()) {
439 // We have a higher precedence op here. Get the rhs operand for the llhs
440 // through parseAffineHighPrecOpExpr.
441 AffineExpr highRes
= parseAffineHighPrecOpExpr(lhs
, hOp
, opLoc
);
445 // If llhs is null, the product forms the first operand of the yet to be
446 // found expression. If non-null, the op to associate with llhs is llhsOp.
448 llhs
? getAffineBinaryOpExpr(llhsOp
, llhs
, highRes
) : highRes
;
450 // Recurse for subsequent low prec op's after the affine high prec op
452 if (AffineLowPrecOp nextOp
= consumeIfLowPrecOp())
453 return parseAffineLowPrecOpExpr(expr
, nextOp
);
456 // Last operand in the expression list.
458 return getAffineBinaryOpExpr(llhsOp
, llhs
, lhs
);
459 // No llhs, 'lhs' itself is the expression.
463 /// Parse an affine expression.
464 /// affine-expr ::= `(` affine-expr `)`
465 /// | `-` affine-expr
466 /// | affine-expr `+` affine-expr
467 /// | affine-expr `-` affine-expr
468 /// | affine-expr `*` affine-expr
469 /// | affine-expr `floordiv` affine-expr
470 /// | affine-expr `ceildiv` affine-expr
471 /// | affine-expr `mod` affine-expr
473 /// | integer-literal
475 /// Additional conditions are checked depending on the production. For eg.,
476 /// one of the operands for `*` has to be either constant/symbolic; the second
477 /// operand for floordiv, ceildiv, and mod has to be a positive integer.
478 AffineExpr
AffineParser::parseAffineExpr() {
479 return parseAffineLowPrecOpExpr(nullptr, AffineLowPrecOp::LNoOp
);
482 /// Parse a dim or symbol from the lists appearing before the actual
483 /// expressions of the affine map. Update our state to store the
484 /// dimensional/symbolic identifier.
485 ParseResult
AffineParser::parseIdentifierDefinition(AffineExpr idExpr
) {
486 if (!isIdentifier(getToken()))
487 return emitWrongTokenError("expected bare identifier");
489 auto name
= getTokenSpelling();
490 for (auto entry
: dimsAndSymbols
) {
491 if (entry
.first
== name
)
492 return emitError("redefinition of identifier '" + name
+ "'");
496 dimsAndSymbols
.push_back({name
, idExpr
});
500 /// Parse the list of dimensional identifiers to an affine map.
501 ParseResult
AffineParser::parseDimIdList(unsigned &numDims
) {
502 auto parseElt
= [&]() -> ParseResult
{
503 auto dimension
= getAffineDimExpr(numDims
++, getContext());
504 return parseIdentifierDefinition(dimension
);
506 return parseCommaSeparatedList(Delimiter::Paren
, parseElt
,
507 " in dimensional identifier list");
510 /// Parse the list of symbolic identifiers to an affine map.
511 ParseResult
AffineParser::parseSymbolIdList(unsigned &numSymbols
) {
512 auto parseElt
= [&]() -> ParseResult
{
513 auto symbol
= getAffineSymbolExpr(numSymbols
++, getContext());
514 return parseIdentifierDefinition(symbol
);
516 return parseCommaSeparatedList(Delimiter::Square
, parseElt
,
520 /// Parse the list of symbolic identifiers to an affine map.
522 AffineParser::parseDimAndOptionalSymbolIdList(unsigned &numDims
,
523 unsigned &numSymbols
) {
524 if (parseDimIdList(numDims
)) {
527 if (!getToken().is(Token::l_square
)) {
531 return parseSymbolIdList(numSymbols
);
534 /// Parses an ambiguous affine map or integer set definition inline.
535 ParseResult
AffineParser::parseAffineMapOrIntegerSetInline(AffineMap
&map
,
537 unsigned numDims
= 0, numSymbols
= 0;
539 // List of dimensional and optional symbol identifiers.
540 if (parseDimAndOptionalSymbolIdList(numDims
, numSymbols
))
543 if (consumeIf(Token::arrow
))
544 return parseAffineMapRange(numDims
, numSymbols
, map
);
546 if (parseToken(Token::colon
, "expected '->' or ':'"))
548 return parseIntegerSetConstraints(numDims
, numSymbols
, set
);
551 /// Parse an affine expresion definition inline, with given symbols.
552 ParseResult
AffineParser::parseAffineExprInline(
553 ArrayRef
<std::pair
<StringRef
, AffineExpr
>> symbolSet
, AffineExpr
&expr
) {
554 dimsAndSymbols
.assign(symbolSet
.begin(), symbolSet
.end());
555 expr
= parseAffineExpr();
556 return success(expr
!= nullptr);
559 /// Parse an AffineMap where the dim and symbol identifiers are SSA ids.
561 AffineParser::parseAffineMapOfSSAIds(AffineMap
&map
,
562 OpAsmParser::Delimiter delimiter
) {
564 SmallVector
<AffineExpr
, 4> exprs
;
565 auto parseElt
= [&]() -> ParseResult
{
566 auto elt
= parseAffineExpr();
567 exprs
.push_back(elt
);
568 return elt
? success() : failure();
571 // Parse a multi-dimensional affine expression (a comma-separated list of
572 // 1-d affine expressions); the list can be empty. Grammar:
573 // multi-dim-affine-expr ::= `(` `)`
574 // | `(` affine-expr (`,` affine-expr)* `)`
575 if (parseCommaSeparatedList(delimiter
, parseElt
, " in affine map"))
578 // Parsed a valid affine map.
579 map
= AffineMap::get(numDimOperands
, dimsAndSymbols
.size() - numDimOperands
,
580 exprs
, getContext());
584 /// Parse an AffineExpr where the dim and symbol identifiers are SSA ids.
585 ParseResult
AffineParser::parseAffineExprOfSSAIds(AffineExpr
&expr
) {
586 expr
= parseAffineExpr();
587 return success(expr
!= nullptr);
590 /// Parse the range and sizes affine map definition inline.
592 /// affine-map ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
594 /// multi-dim-affine-expr ::= `(` `)`
595 /// multi-dim-affine-expr ::= `(` affine-expr (`,` affine-expr)* `)`
596 ParseResult
AffineParser::parseAffineMapRange(unsigned numDims
,
599 SmallVector
<AffineExpr
, 4> exprs
;
600 auto parseElt
= [&]() -> ParseResult
{
601 auto elt
= parseAffineExpr();
602 ParseResult res
= elt
? success() : failure();
603 exprs
.push_back(elt
);
607 // Parse a multi-dimensional affine expression (a comma-separated list of
608 // 1-d affine expressions). Grammar:
609 // multi-dim-affine-expr ::= `(` `)`
610 // | `(` affine-expr (`,` affine-expr)* `)`
611 if (parseCommaSeparatedList(Delimiter::Paren
, parseElt
,
612 " in affine map range"))
615 // Parsed a valid affine map.
616 result
= AffineMap::get(numDims
, numSymbols
, exprs
, getContext());
620 /// Parse an affine constraint.
621 /// affine-constraint ::= affine-expr `>=` `affine-expr`
622 /// | affine-expr `<=` `affine-expr`
623 /// | affine-expr `==` `affine-expr`
625 /// The constraint is normalized to
626 /// affine-constraint ::= affine-expr `>=` `0`
627 /// | affine-expr `==` `0`
628 /// before returning.
630 /// isEq is set to true if the parsed constraint is an equality, false if it
631 /// is an inequality (greater than or equal).
633 AffineExpr
AffineParser::parseAffineConstraint(bool *isEq
) {
634 AffineExpr lhsExpr
= parseAffineExpr();
638 // affine-constraint ::= `affine-expr` `>=` `affine-expr`
639 if (consumeIf(Token::greater
) && consumeIf(Token::equal
)) {
640 AffineExpr rhsExpr
= parseAffineExpr();
644 return lhsExpr
- rhsExpr
;
647 // affine-constraint ::= `affine-expr` `<=` `affine-expr`
648 if (consumeIf(Token::less
) && consumeIf(Token::equal
)) {
649 AffineExpr rhsExpr
= parseAffineExpr();
653 return rhsExpr
- lhsExpr
;
656 // affine-constraint ::= `affine-expr` `==` `affine-expr`
657 if (consumeIf(Token::equal
) && consumeIf(Token::equal
)) {
658 AffineExpr rhsExpr
= parseAffineExpr();
662 return lhsExpr
- rhsExpr
;
665 return emitError("expected '== affine-expr' or '>= affine-expr' at end of "
666 "affine constraint"),
670 /// Parse the constraints that are part of an integer set definition.
671 /// integer-set-inline
672 /// ::= dim-and-symbol-id-lists `:`
673 /// '(' affine-constraint-conjunction? ')'
674 /// affine-constraint-conjunction ::= affine-constraint (`,`
675 /// affine-constraint)*
677 ParseResult
AffineParser::parseIntegerSetConstraints(unsigned numDims
,
679 IntegerSet
&result
) {
680 SmallVector
<AffineExpr
, 4> constraints
;
681 SmallVector
<bool, 4> isEqs
;
682 auto parseElt
= [&]() -> ParseResult
{
684 auto elt
= parseAffineConstraint(&isEq
);
685 ParseResult res
= elt
? success() : failure();
687 constraints
.push_back(elt
);
688 isEqs
.push_back(isEq
);
693 // Parse a list of affine constraints (comma-separated).
694 if (parseCommaSeparatedList(Delimiter::Paren
, parseElt
,
695 " in integer set constraint list"))
698 // If no constraints were parsed, then treat this as a degenerate 'true' case.
699 if (constraints
.empty()) {
701 auto zero
= getAffineConstantExpr(0, getContext());
702 result
= IntegerSet::get(numDims
, numSymbols
, zero
, true);
706 // Parsed a valid integer set.
707 result
= IntegerSet::get(numDims
, numSymbols
, constraints
, isEqs
);
711 //===----------------------------------------------------------------------===//
713 //===----------------------------------------------------------------------===//
715 /// Parse an ambiguous reference to either and affine map or an integer set.
716 ParseResult
Parser::parseAffineMapOrIntegerSetReference(AffineMap
&map
,
718 return AffineParser(state
).parseAffineMapOrIntegerSetInline(map
, set
);
720 ParseResult
Parser::parseAffineMapReference(AffineMap
&map
) {
721 SMLoc curLoc
= getToken().getLoc();
723 if (parseAffineMapOrIntegerSetReference(map
, set
))
726 return emitError(curLoc
, "expected AffineMap, but got IntegerSet");
729 ParseResult
Parser::parseAffineExprReference(
730 ArrayRef
<std::pair
<StringRef
, AffineExpr
>> symbolSet
, AffineExpr
&expr
) {
731 return AffineParser(state
).parseAffineExprInline(symbolSet
, expr
);
733 ParseResult
Parser::parseIntegerSetReference(IntegerSet
&set
) {
734 SMLoc curLoc
= getToken().getLoc();
736 if (parseAffineMapOrIntegerSetReference(map
, set
))
739 return emitError(curLoc
, "expected IntegerSet, but got AffineMap");
743 /// Parse an AffineMap of SSA ids. The callback 'parseElement' is used to
744 /// parse SSA value uses encountered while parsing affine expressions.
746 Parser::parseAffineMapOfSSAIds(AffineMap
&map
,
747 function_ref
<ParseResult(bool)> parseElement
,
748 OpAsmParser::Delimiter delimiter
) {
749 return AffineParser(state
, /*allowParsingSSAIds=*/true, parseElement
)
750 .parseAffineMapOfSSAIds(map
, delimiter
);
753 /// Parse an AffineExpr of SSA ids. The callback `parseElement` is used to parse
754 /// SSA value uses encountered while parsing.
756 Parser::parseAffineExprOfSSAIds(AffineExpr
&expr
,
757 function_ref
<ParseResult(bool)> parseElement
) {
758 return AffineParser(state
, /*allowParsingSSAIds=*/true, parseElement
)
759 .parseAffineExprOfSSAIds(expr
);
762 static void parseAffineMapOrIntegerSet(StringRef inputStr
, MLIRContext
*context
,
763 AffineMap
&map
, IntegerSet
&set
) {
764 llvm::SourceMgr sourceMgr
;
765 auto memBuffer
= llvm::MemoryBuffer::getMemBuffer(
766 inputStr
, /*BufferName=*/"<mlir_parser_buffer>",
767 /*RequiresNullTerminator=*/false);
768 sourceMgr
.AddNewSourceBuffer(std::move(memBuffer
), SMLoc());
769 SymbolState symbolState
;
770 ParserConfig
config(context
);
771 ParserState
state(sourceMgr
, config
, symbolState
, /*asmState=*/nullptr,
772 /*codeCompleteContext=*/nullptr);
773 Parser
parser(state
);
775 SourceMgrDiagnosticHandler
handler(sourceMgr
, context
, llvm::errs());
776 if (parser
.parseAffineMapOrIntegerSetReference(map
, set
))
779 Token endTok
= parser
.getToken();
780 if (endTok
.isNot(Token::eof
)) {
781 parser
.emitError(endTok
.getLoc(), "encountered unexpected token");
786 AffineMap
mlir::parseAffineMap(StringRef inputStr
, MLIRContext
*context
) {
789 parseAffineMapOrIntegerSet(inputStr
, context
, map
, set
);
791 "expected string to represent AffineMap, but got IntegerSet instead");
795 IntegerSet
mlir::parseIntegerSet(StringRef inputStr
, MLIRContext
*context
) {
798 parseAffineMapOrIntegerSet(inputStr
, context
, map
, set
);
800 "expected string to represent IntegerSet, but got AffineMap instead");