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 {
62 ParserState &state,
bool allowParsingSSAIds =
false,
63 function_ref<FailureOr<OpAsmParser::UnresolvedOperand>()> parseElement =
65 function_ref<
void(
bool, OpAsmParser::UnresolvedOperand)> addOperand =
67 : Parser(state), allowParsingSSAIds(allowParsingSSAIds),
68 parseElement(parseElement), addOperand(addOperand) {}
70 ParseResult parseAffineMapRange(
unsigned numDims,
unsigned numSymbols,
72 ParseResult parseAffineMapOrIntegerSetInline(AffineMap &map, IntegerSet &set);
74 parseAffineExprInline(ArrayRef<std::pair<StringRef, AffineExpr>> symbolSet,
76 ParseResult parseIntegerSetConstraints(
unsigned numDims,
unsigned numSymbols,
78 ParseResult parseAffineMapOfSSAIds(AffineMap &map,
79 OpAsmParser::Delimiter delimiter);
80 ParseResult parseAffineExprOfSSAIds(AffineExpr &expr);
84 AffineLowPrecOp consumeIfLowPrecOp();
85 AffineHighPrecOp consumeIfHighPrecOp();
88 ParseResult parseDimIdList(
unsigned &numDims);
89 ParseResult parseSymbolIdList(
unsigned &numSymbols);
90 ParseResult parseDimAndOptionalSymbolIdList(
unsigned &numDims,
91 unsigned &numSymbols);
92 ParseResult parseIdentifierDefinition(AffineExpr idExpr);
94 AffineExpr parseAffineExpr();
95 AffineExpr parseParentheticalExpr();
96 AffineExpr parseNegateExpression(AffineExpr
lhs);
97 AffineExpr parseIntegerExpr();
98 AffineExpr parseBareIdExpr();
99 AffineExpr parseSSAIdExpr(
bool isSymbol);
100 AffineExpr parseSymbolSSAIdExpr();
103 AffineExpr
rhs, SMLoc opLoc);
106 AffineExpr parseAffineOperandExpr(AffineExpr
lhs);
107 AffineExpr parseAffineLowPrecOpExpr(AffineExpr llhs, AffineLowPrecOp llhsOp);
108 AffineExpr parseAffineHighPrecOpExpr(AffineExpr llhs, AffineHighPrecOp llhsOp,
110 AffineExpr parseAffineConstraint(
bool *isEq);
113 bool allowParsingSSAIds;
115 function_ref<void(
bool, OpAsmParser::UnresolvedOperand)> addOperand;
116 unsigned numDimOperands = 0;
117 unsigned numSymbolOperands = 0;
118 SmallVector<std::pair<std::pair<StringRef, unsigned>, AffineExpr>, 4>
126AffineExpr AffineParser::getAffineBinaryOpExpr(AffineHighPrecOp op,
132 if (!
lhs.isSymbolicOrConstant() && !
rhs.isSymbolicOrConstant()) {
133 emitError(opLoc,
"non-affine expression: at least one of the multiply "
134 "operands has to be either a constant or symbolic");
139 if (!
rhs.isSymbolicOrConstant()) {
140 emitError(opLoc,
"non-affine expression: right operand of floordiv "
141 "has to be either a constant or symbolic");
146 if (!
rhs.isSymbolicOrConstant()) {
147 emitError(opLoc,
"non-affine expression: right operand of ceildiv "
148 "has to be either a constant or symbolic");
153 if (!
rhs.isSymbolicOrConstant()) {
154 emitError(opLoc,
"non-affine expression: right operand of mod "
155 "has to be either a constant or symbolic");
160 llvm_unreachable(
"can't create affine expression for null high prec op");
163 llvm_unreachable(
"Unknown AffineHighPrecOp");
167AffineExpr AffineParser::getAffineBinaryOpExpr(AffineLowPrecOp op,
168 AffineExpr
lhs, AffineExpr
rhs) {
170 case AffineLowPrecOp::Add:
172 case AffineLowPrecOp::Sub:
174 case AffineLowPrecOp::LNoOp:
175 llvm_unreachable(
"can't create affine expression for null low prec op");
178 llvm_unreachable(
"Unknown AffineLowPrecOp");
183AffineLowPrecOp AffineParser::consumeIfLowPrecOp() {
184 switch (getToken().getKind()) {
186 consumeToken(Token::plus);
187 return AffineLowPrecOp::Add;
189 consumeToken(Token::minus);
190 return AffineLowPrecOp::Sub;
192 return AffineLowPrecOp::LNoOp;
198AffineHighPrecOp AffineParser::consumeIfHighPrecOp() {
199 switch (getToken().getKind()) {
201 consumeToken(Token::star);
203 case Token::kw_floordiv:
204 consumeToken(Token::kw_floordiv);
206 case Token::kw_ceildiv:
207 consumeToken(Token::kw_ceildiv);
210 consumeToken(Token::kw_mod);
226AffineExpr AffineParser::parseAffineHighPrecOpExpr(AffineExpr llhs,
227 AffineHighPrecOp llhsOp,
229 AffineExpr
lhs = parseAffineOperandExpr(llhs);
234 auto opLoc = getToken().getLoc();
235 if (AffineHighPrecOp op = consumeIfHighPrecOp()) {
240 return parseAffineHighPrecOpExpr(expr, op, opLoc);
243 return parseAffineHighPrecOpExpr(
lhs, op, opLoc);
257AffineExpr AffineParser::parseParentheticalExpr() {
258 if (parseToken(Token::l_paren,
"expected '('"))
260 if (getToken().is(Token::r_paren))
261 return emitError(
"no expression inside parentheses"),
nullptr;
263 auto expr = parseAffineExpr();
264 if (!expr || parseToken(Token::r_paren,
"expected ')'"))
273AffineExpr AffineParser::parseNegateExpression(AffineExpr
lhs) {
274 if (parseToken(Token::minus,
"expected '-'"))
277 AffineExpr operand = parseAffineOperandExpr(
lhs);
284 return emitError(
"missing operand of negation"),
nullptr;
285 return (-1) * operand;
292 return token.
isAny(Token::bare_identifier, Token::inttype) ||
299AffineExpr AffineParser::parseBareIdExpr() {
301 return emitWrongTokenError(
"expected bare identifier"),
nullptr;
303 StringRef sRef = getTokenSpelling();
304 for (
auto entry : dimsAndSymbols) {
305 if (entry.first.first == sRef) {
311 return emitWrongTokenError(
"use of undeclared identifier"),
nullptr;
315AffineExpr AffineParser::parseSSAIdExpr(
bool isSymbol) {
316 if (!allowParsingSSAIds)
317 return emitWrongTokenError(
"unexpected ssa identifier"),
nullptr;
318 if (getToken().isNot(Token::percent_identifier))
319 return emitWrongTokenError(
"expected ssa identifier"),
nullptr;
320 FailureOr<OpAsmParser::UnresolvedOperand> operand = parseElement();
324 for (
auto entry : dimsAndSymbols)
325 if (entry.first.first == operand->name &&
326 entry.first.second == operand->number)
330 addOperand(isSymbol, *operand);
331 auto idExpr = isSymbol
334 dimsAndSymbols.push_back({{operand->name, operand->number}, idExpr});
338AffineExpr AffineParser::parseSymbolSSAIdExpr() {
339 if (parseToken(Token::kw_symbol,
"expected symbol keyword") ||
340 parseToken(Token::l_paren,
"expected '(' at start of SSA symbol"))
342 AffineExpr symbolExpr = parseSSAIdExpr(
true);
345 if (parseToken(Token::r_paren,
"expected ')' at end of SSA symbol"))
353AffineExpr AffineParser::parseIntegerExpr() {
354 auto val = getToken().getUInt64IntegerValue();
360 if (!val.has_value() ||
361 (
static_cast<int64_t
>(*val) < 0 &&
362 *val !=
static_cast<uint64_t
>(std::numeric_limits<int64_t>::min())))
363 return emitError(
"constant too large for index"),
nullptr;
365 consumeToken(Token::integer);
366 return builder.getAffineConstantExpr((int64_t)*val);
378AffineExpr AffineParser::parseAffineOperandExpr(AffineExpr
lhs) {
379 switch (getToken().getKind()) {
380 case Token::kw_symbol:
381 return parseSymbolSSAIdExpr();
382 case Token::percent_identifier:
383 return parseSSAIdExpr(
false);
385 return parseIntegerExpr();
387 return parseParentheticalExpr();
389 return parseNegateExpression(
lhs);
390 case Token::kw_ceildiv:
391 case Token::kw_floordiv:
394 return parseBareIdExpr();
398 emitError(
"missing right operand of binary operator");
400 emitError(
"missing left operand of binary operator");
405 return parseBareIdExpr();
408 emitError(
"missing right operand of binary operator");
436AffineExpr AffineParser::parseAffineLowPrecOpExpr(AffineExpr llhs,
437 AffineLowPrecOp llhsOp) {
439 if (!(
lhs = parseAffineOperandExpr(llhs)))
443 if (AffineLowPrecOp lOp = consumeIfLowPrecOp()) {
446 return parseAffineLowPrecOpExpr(sum, lOp);
449 return parseAffineLowPrecOpExpr(
lhs, lOp);
451 auto opLoc = getToken().getLoc();
452 if (AffineHighPrecOp hOp = consumeIfHighPrecOp()) {
455 AffineExpr highRes = parseAffineHighPrecOpExpr(
lhs, hOp, opLoc);
466 if (AffineLowPrecOp nextOp = consumeIfLowPrecOp())
467 return parseAffineLowPrecOpExpr(expr, nextOp);
492AffineExpr AffineParser::parseAffineExpr() {
493 return parseAffineLowPrecOpExpr(
nullptr, AffineLowPrecOp::LNoOp);
499ParseResult AffineParser::parseIdentifierDefinition(AffineExpr idExpr) {
501 return emitWrongTokenError(
"expected bare identifier");
503 auto name = getTokenSpelling();
504 for (
auto entry : dimsAndSymbols) {
505 if (entry.first.first == name)
506 return emitError(
"redefinition of identifier '" + name +
"'");
510 dimsAndSymbols.push_back({{name, 0}, idExpr});
515ParseResult AffineParser::parseDimIdList(
unsigned &numDims) {
516 auto parseElt = [&]() -> ParseResult {
518 return parseIdentifierDefinition(dimension);
521 " in dimensional identifier list");
525ParseResult AffineParser::parseSymbolIdList(
unsigned &numSymbols) {
526 auto parseElt = [&]() -> ParseResult {
528 return parseIdentifierDefinition(symbol);
536AffineParser::parseDimAndOptionalSymbolIdList(
unsigned &numDims,
537 unsigned &numSymbols) {
538 if (parseDimIdList(numDims)) {
541 if (!getToken().is(Token::l_square)) {
545 return parseSymbolIdList(numSymbols);
549ParseResult AffineParser::parseAffineMapOrIntegerSetInline(AffineMap &map,
551 unsigned numDims = 0, numSymbols = 0;
554 if (parseDimAndOptionalSymbolIdList(numDims, numSymbols))
557 if (consumeIf(Token::arrow))
558 return parseAffineMapRange(numDims, numSymbols, map);
560 if (parseToken(Token::colon,
"expected '->' or ':'"))
562 return parseIntegerSetConstraints(numDims, numSymbols, set);
566ParseResult AffineParser::parseAffineExprInline(
567 ArrayRef<std::pair<StringRef, AffineExpr>> symbolSet, AffineExpr &expr) {
568 for (
const auto &[name, expr] : symbolSet)
569 dimsAndSymbols.push_back({{name, 0}, expr});
570 expr = parseAffineExpr();
571 return success(expr !=
nullptr);
576AffineParser::parseAffineMapOfSSAIds(AffineMap &map,
577 OpAsmParser::Delimiter delimiter) {
579 SmallVector<AffineExpr, 4> exprs;
580 auto parseElt = [&]() -> ParseResult {
581 auto elt = parseAffineExpr();
582 exprs.push_back(elt);
583 return elt ?
success() : failure();
594 map =
AffineMap::get(numDimOperands, dimsAndSymbols.size() - numDimOperands,
600ParseResult AffineParser::parseAffineExprOfSSAIds(AffineExpr &expr) {
601 expr = parseAffineExpr();
602 return success(expr !=
nullptr);
611ParseResult AffineParser::parseAffineMapRange(
unsigned numDims,
614 SmallVector<AffineExpr, 4> exprs;
615 auto parseElt = [&]() -> ParseResult {
616 auto elt = parseAffineExpr();
617 ParseResult res = elt ?
success() : failure();
618 exprs.push_back(elt);
627 " in affine map range"))
648AffineExpr AffineParser::parseAffineConstraint(
bool *isEq) {
649 AffineExpr lhsExpr = parseAffineExpr();
654 if (consumeIf(Token::greater) && consumeIf(Token::equal)) {
655 AffineExpr rhsExpr = parseAffineExpr();
659 return lhsExpr - rhsExpr;
663 if (consumeIf(Token::less) && consumeIf(Token::equal)) {
664 AffineExpr rhsExpr = parseAffineExpr();
668 return rhsExpr - lhsExpr;
672 if (consumeIf(Token::equal) && consumeIf(Token::equal)) {
673 AffineExpr rhsExpr = parseAffineExpr();
677 return lhsExpr - rhsExpr;
680 return emitError(
"expected '== affine-expr' or '>= affine-expr' at end of "
681 "affine constraint"),
692ParseResult AffineParser::parseIntegerSetConstraints(
unsigned numDims,
695 SmallVector<AffineExpr, 4> constraints;
696 SmallVector<bool, 4> isEqs;
697 auto parseElt = [&]() -> ParseResult {
699 auto elt = parseAffineConstraint(&isEq);
700 ParseResult res = elt ?
success() : failure();
702 constraints.push_back(elt);
703 isEqs.push_back(isEq);
710 " in integer set constraint list"))
714 if (constraints.empty()) {
733 return AffineParser(
state).parseAffineMapOrIntegerSetInline(map, set);
741 return emitError(curLoc,
"expected AffineMap, but got IntegerSet");
746 return AffineParser(
state).parseAffineExprInline(symbolSet, expr);
754 return emitError(curLoc,
"expected IntegerSet, but got AffineMap");
762 function_ref<FailureOr<OpAsmParser::UnresolvedOperand>()> parseElement,
765 return AffineParser(
state,
true, parseElement,
767 .parseAffineMapOfSSAIds(map, delimiter);
774 function_ref<FailureOr<OpAsmParser::UnresolvedOperand>()> parseElement,
776 return AffineParser(
state,
true, parseElement,
778 .parseAffineExprOfSSAIds(expr);
783 llvm::SourceMgr sourceMgr;
784 auto memBuffer = llvm::MemoryBuffer::getMemBuffer(
785 inputStr,
"<mlir_parser_buffer>",
787 sourceMgr.AddNewSourceBuffer(std::move(memBuffer), SMLoc());
790 ParserState state(sourceMgr, config, symbolState,
nullptr,
799 if (endTok.
isNot(Token::eof)) {
810 "expected string to represent AffineMap, but got IntegerSet instead");
819 "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 parseAffineMapOfSSAIds(AffineMap &map, function_ref< FailureOr< OpAsmParser::UnresolvedOperand >()> parseElement, function_ref< void(bool, OpAsmParser::UnresolvedOperand)> addOperand, Delimiter delimiter)
Parse an AffineMap where the dim and symbol identifiers are SSA ids.
ParseResult parseAffineMapOrIntegerSetReference(AffineMap &map, IntegerSet &set)
Parse a reference to either an affine map, expr, or an integer set.
ParseResult parseAffineExprOfSSAIds(AffineExpr &expr, function_ref< FailureOr< OpAsmParser::UnresolvedOperand >()> parseElement, function_ref< void(bool, OpAsmParser::UnresolvedOperand)> addOperand)
Parse an AffineExpr where 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.
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 is the representation of an operand reference.
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.